LCOV - code coverage report
Current view: top level - drivers/tty/vt - vt.c (source / functions) Hit Total Coverage
Test: Real Lines: 777 2072 37.5 %
Date: 2020-10-17 15:46:16 Functions: 9 136 6.6 %
Legend: Neither, QEMU, Real, Both Branches: 0 0 -

           Branch data     Line data    Source code
       1                 :            : // SPDX-License-Identifier: GPL-2.0
       2                 :            : /*
       3                 :            :  *  Copyright (C) 1991, 1992  Linus Torvalds
       4                 :            :  */
       5                 :            : 
       6                 :            : /*
       7                 :            :  * Hopefully this will be a rather complete VT102 implementation.
       8                 :            :  *
       9                 :            :  * Beeping thanks to John T Kohl.
      10                 :            :  *
      11                 :            :  * Virtual Consoles, Screen Blanking, Screen Dumping, Color, Graphics
      12                 :            :  *   Chars, and VT100 enhancements by Peter MacDonald.
      13                 :            :  *
      14                 :            :  * Copy and paste function by Andrew Haylett,
      15                 :            :  *   some enhancements by Alessandro Rubini.
      16                 :            :  *
      17                 :            :  * Code to check for different video-cards mostly by Galen Hunt,
      18                 :            :  * <g-hunt@ee.utah.edu>
      19                 :            :  *
      20                 :            :  * Rudimentary ISO 10646/Unicode/UTF-8 character set support by
      21                 :            :  * Markus Kuhn, <mskuhn@immd4.informatik.uni-erlangen.de>.
      22                 :            :  *
      23                 :            :  * Dynamic allocation of consoles, aeb@cwi.nl, May 1994
      24                 :            :  * Resizing of consoles, aeb, 940926
      25                 :            :  *
      26                 :            :  * Code for xterm like mouse click reporting by Peter Orbaek 20-Jul-94
      27                 :            :  * <poe@daimi.aau.dk>
      28                 :            :  *
      29                 :            :  * User-defined bell sound, new setterm control sequences and printk
      30                 :            :  * redirection by Martin Mares <mj@k332.feld.cvut.cz> 19-Nov-95
      31                 :            :  *
      32                 :            :  * APM screenblank bug fixed Takashi Manabe <manabe@roy.dsl.tutics.tut.jp>
      33                 :            :  *
      34                 :            :  * Merge with the abstract console driver by Geert Uytterhoeven
      35                 :            :  * <geert@linux-m68k.org>, Jan 1997.
      36                 :            :  *
      37                 :            :  *   Original m68k console driver modifications by
      38                 :            :  *
      39                 :            :  *     - Arno Griffioen <arno@usn.nl>
      40                 :            :  *     - David Carter <carter@cs.bris.ac.uk>
      41                 :            :  * 
      42                 :            :  *   The abstract console driver provides a generic interface for a text
      43                 :            :  *   console. It supports VGA text mode, frame buffer based graphical consoles
      44                 :            :  *   and special graphics processors that are only accessible through some
      45                 :            :  *   registers (e.g. a TMS340x0 GSP).
      46                 :            :  *
      47                 :            :  *   The interface to the hardware is specified using a special structure
      48                 :            :  *   (struct consw) which contains function pointers to console operations
      49                 :            :  *   (see <linux/console.h> for more information).
      50                 :            :  *
      51                 :            :  * Support for changeable cursor shape
      52                 :            :  * by Pavel Machek <pavel@atrey.karlin.mff.cuni.cz>, August 1997
      53                 :            :  *
      54                 :            :  * Ported to i386 and con_scrolldelta fixed
      55                 :            :  * by Emmanuel Marty <core@ggi-project.org>, April 1998
      56                 :            :  *
      57                 :            :  * Resurrected character buffers in videoram plus lots of other trickery
      58                 :            :  * by Martin Mares <mj@atrey.karlin.mff.cuni.cz>, July 1998
      59                 :            :  *
      60                 :            :  * Removed old-style timers, introduced console_timer, made timer
      61                 :            :  * deletion SMP-safe.  17Jun00, Andrew Morton
      62                 :            :  *
      63                 :            :  * Removed console_lock, enabled interrupts across all console operations
      64                 :            :  * 13 March 2001, Andrew Morton
      65                 :            :  *
      66                 :            :  * Fixed UTF-8 mode so alternate charset modes always work according
      67                 :            :  * to control sequences interpreted in do_con_trol function
      68                 :            :  * preserving backward VT100 semigraphics compatibility,
      69                 :            :  * malformed UTF sequences represented as sequences of replacement glyphs,
      70                 :            :  * original codes or '?' as a last resort if replacement glyph is undefined
      71                 :            :  * by Adam Tla/lka <atlka@pg.gda.pl>, Aug 2006
      72                 :            :  */
      73                 :            : 
      74                 :            : #include <linux/module.h>
      75                 :            : #include <linux/types.h>
      76                 :            : #include <linux/sched/signal.h>
      77                 :            : #include <linux/tty.h>
      78                 :            : #include <linux/tty_flip.h>
      79                 :            : #include <linux/kernel.h>
      80                 :            : #include <linux/string.h>
      81                 :            : #include <linux/errno.h>
      82                 :            : #include <linux/kd.h>
      83                 :            : #include <linux/slab.h>
      84                 :            : #include <linux/vmalloc.h>
      85                 :            : #include <linux/major.h>
      86                 :            : #include <linux/mm.h>
      87                 :            : #include <linux/console.h>
      88                 :            : #include <linux/init.h>
      89                 :            : #include <linux/mutex.h>
      90                 :            : #include <linux/vt_kern.h>
      91                 :            : #include <linux/selection.h>
      92                 :            : #include <linux/tiocl.h>
      93                 :            : #include <linux/kbd_kern.h>
      94                 :            : #include <linux/consolemap.h>
      95                 :            : #include <linux/timer.h>
      96                 :            : #include <linux/interrupt.h>
      97                 :            : #include <linux/workqueue.h>
      98                 :            : #include <linux/pm.h>
      99                 :            : #include <linux/font.h>
     100                 :            : #include <linux/bitops.h>
     101                 :            : #include <linux/notifier.h>
     102                 :            : #include <linux/device.h>
     103                 :            : #include <linux/io.h>
     104                 :            : #include <linux/uaccess.h>
     105                 :            : #include <linux/kdb.h>
     106                 :            : #include <linux/ctype.h>
     107                 :            : #include <linux/bsearch.h>
     108                 :            : #include <linux/gcd.h>
     109                 :            : 
     110                 :            : #define MAX_NR_CON_DRIVER 16
     111                 :            : 
     112                 :            : #define CON_DRIVER_FLAG_MODULE 1
     113                 :            : #define CON_DRIVER_FLAG_INIT   2
     114                 :            : #define CON_DRIVER_FLAG_ATTR   4
     115                 :            : #define CON_DRIVER_FLAG_ZOMBIE 8
     116                 :            : 
     117                 :            : struct con_driver {
     118                 :            :         const struct consw *con;
     119                 :            :         const char *desc;
     120                 :            :         struct device *dev;
     121                 :            :         int node;
     122                 :            :         int first;
     123                 :            :         int last;
     124                 :            :         int flag;
     125                 :            : };
     126                 :            : 
     127                 :            : static struct con_driver registered_con_driver[MAX_NR_CON_DRIVER];
     128                 :            : const struct consw *conswitchp;
     129                 :            : 
     130                 :            : /* A bitmap for codes <32. A bit of 1 indicates that the code
     131                 :            :  * corresponding to that bit number invokes some special action
     132                 :            :  * (such as cursor movement) and should not be displayed as a
     133                 :            :  * glyph unless the disp_ctrl mode is explicitly enabled.
     134                 :            :  */
     135                 :            : #define CTRL_ACTION 0x0d00ff81
     136                 :            : #define CTRL_ALWAYS 0x0800f501  /* Cannot be overridden by disp_ctrl */
     137                 :            : 
     138                 :            : /*
     139                 :            :  * Here is the default bell parameters: 750HZ, 1/8th of a second
     140                 :            :  */
     141                 :            : #define DEFAULT_BELL_PITCH      750
     142                 :            : #define DEFAULT_BELL_DURATION   (HZ/8)
     143                 :            : #define DEFAULT_CURSOR_BLINK_MS 200
     144                 :            : 
     145                 :            : struct vc vc_cons [MAX_NR_CONSOLES];
     146                 :            : 
     147                 :            : #ifndef VT_SINGLE_DRIVER
     148                 :            : static const struct consw *con_driver_map[MAX_NR_CONSOLES];
     149                 :            : #endif
     150                 :            : 
     151                 :            : static int con_open(struct tty_struct *, struct file *);
     152                 :            : static void vc_init(struct vc_data *vc, unsigned int rows,
     153                 :            :                     unsigned int cols, int do_clear);
     154                 :            : static void gotoxy(struct vc_data *vc, int new_x, int new_y);
     155                 :            : static void save_cur(struct vc_data *vc);
     156                 :            : static void reset_terminal(struct vc_data *vc, int do_clear);
     157                 :            : static void con_flush_chars(struct tty_struct *tty);
     158                 :            : static int set_vesa_blanking(char __user *p);
     159                 :            : static void set_cursor(struct vc_data *vc);
     160                 :            : static void hide_cursor(struct vc_data *vc);
     161                 :            : static void console_callback(struct work_struct *ignored);
     162                 :            : static void con_driver_unregister_callback(struct work_struct *ignored);
     163                 :            : static void blank_screen_t(struct timer_list *unused);
     164                 :            : static void set_palette(struct vc_data *vc);
     165                 :            : 
     166                 :            : #define vt_get_kmsg_redirect() vt_kmsg_redirect(-1)
     167                 :            : 
     168                 :            : static int printable;           /* Is console ready for printing? */
     169                 :            : int default_utf8 = true;
     170                 :            : module_param(default_utf8, int, S_IRUGO | S_IWUSR);
     171                 :            : int global_cursor_default = -1;
     172                 :            : module_param(global_cursor_default, int, S_IRUGO | S_IWUSR);
     173                 :            : 
     174                 :            : static int cur_default = CUR_DEFAULT;
     175                 :            : module_param(cur_default, int, S_IRUGO | S_IWUSR);
     176                 :            : 
     177                 :            : /*
     178                 :            :  * ignore_poke: don't unblank the screen when things are typed.  This is
     179                 :            :  * mainly for the privacy of braille terminal users.
     180                 :            :  */
     181                 :            : static int ignore_poke;
     182                 :            : 
     183                 :            : int do_poke_blanked_console;
     184                 :            : int console_blanked;
     185                 :            : 
     186                 :            : static int vesa_blank_mode; /* 0:none 1:suspendV 2:suspendH 3:powerdown */
     187                 :            : static int vesa_off_interval;
     188                 :            : static int blankinterval;
     189                 :            : core_param(consoleblank, blankinterval, int, 0444);
     190                 :            : 
     191                 :            : static DECLARE_WORK(console_work, console_callback);
     192                 :            : static DECLARE_WORK(con_driver_unregister_work, con_driver_unregister_callback);
     193                 :            : 
     194                 :            : /*
     195                 :            :  * fg_console is the current virtual console,
     196                 :            :  * last_console is the last used one,
     197                 :            :  * want_console is the console we want to switch to,
     198                 :            :  * saved_* variants are for save/restore around kernel debugger enter/leave
     199                 :            :  */
     200                 :            : int fg_console;
     201                 :            : int last_console;
     202                 :            : int want_console = -1;
     203                 :            : static int saved_fg_console;
     204                 :            : static int saved_last_console;
     205                 :            : static int saved_want_console;
     206                 :            : static int saved_vc_mode;
     207                 :            : static int saved_console_blanked;
     208                 :            : 
     209                 :            : /*
     210                 :            :  * For each existing display, we have a pointer to console currently visible
     211                 :            :  * on that display, allowing consoles other than fg_console to be refreshed
     212                 :            :  * appropriately. Unless the low-level driver supplies its own display_fg
     213                 :            :  * variable, we use this one for the "master display".
     214                 :            :  */
     215                 :            : static struct vc_data *master_display_fg;
     216                 :            : 
     217                 :            : /*
     218                 :            :  * Unfortunately, we need to delay tty echo when we're currently writing to the
     219                 :            :  * console since the code is (and always was) not re-entrant, so we schedule
     220                 :            :  * all flip requests to process context with schedule-task() and run it from
     221                 :            :  * console_callback().
     222                 :            :  */
     223                 :            : 
     224                 :            : /*
     225                 :            :  * For the same reason, we defer scrollback to the console callback.
     226                 :            :  */
     227                 :            : static int scrollback_delta;
     228                 :            : 
     229                 :            : /*
     230                 :            :  * Hook so that the power management routines can (un)blank
     231                 :            :  * the console on our behalf.
     232                 :            :  */
     233                 :            : int (*console_blank_hook)(int);
     234                 :            : 
     235                 :            : static DEFINE_TIMER(console_timer, blank_screen_t);
     236                 :            : static int blank_state;
     237                 :            : static int blank_timer_expired;
     238                 :            : enum {
     239                 :            :         blank_off = 0,
     240                 :            :         blank_normal_wait,
     241                 :            :         blank_vesa_wait,
     242                 :            : };
     243                 :            : 
     244                 :            : /*
     245                 :            :  * /sys/class/tty/tty0/
     246                 :            :  *
     247                 :            :  * the attribute 'active' contains the name of the current vc
     248                 :            :  * console and it supports poll() to detect vc switches
     249                 :            :  */
     250                 :            : static struct device *tty0dev;
     251                 :            : 
     252                 :            : /*
     253                 :            :  * Notifier list for console events.
     254                 :            :  */
     255                 :            : static ATOMIC_NOTIFIER_HEAD(vt_notifier_list);
     256                 :            : 
     257                 :          0 : int register_vt_notifier(struct notifier_block *nb)
     258                 :            : {
     259                 :          0 :         return atomic_notifier_chain_register(&vt_notifier_list, nb);
     260                 :            : }
     261                 :            : EXPORT_SYMBOL_GPL(register_vt_notifier);
     262                 :            : 
     263                 :          0 : int unregister_vt_notifier(struct notifier_block *nb)
     264                 :            : {
     265                 :          0 :         return atomic_notifier_chain_unregister(&vt_notifier_list, nb);
     266                 :            : }
     267                 :            : EXPORT_SYMBOL_GPL(unregister_vt_notifier);
     268                 :            : 
     269                 :            : static void notify_write(struct vc_data *vc, unsigned int unicode)
     270                 :            : {
     271                 :          3 :         struct vt_notifier_param param = { .vc = vc, .c = unicode };
     272                 :          3 :         atomic_notifier_call_chain(&vt_notifier_list, VT_WRITE, &param);
     273                 :            : }
     274                 :            : 
     275                 :            : static void notify_update(struct vc_data *vc)
     276                 :            : {
     277                 :          3 :         struct vt_notifier_param param = { .vc = vc };
     278                 :          3 :         atomic_notifier_call_chain(&vt_notifier_list, VT_UPDATE, &param);
     279                 :            : }
     280                 :            : /*
     281                 :            :  *      Low-Level Functions
     282                 :            :  */
     283                 :            : 
     284                 :            : static inline bool con_is_fg(const struct vc_data *vc)
     285                 :            : {
     286                 :          3 :         return vc->vc_num == fg_console;
     287                 :            : }
     288                 :            : 
     289                 :            : static inline bool con_should_update(const struct vc_data *vc)
     290                 :            : {
     291                 :          3 :         return con_is_visible(vc) && !console_blanked;
     292                 :            : }
     293                 :            : 
     294                 :            : static inline unsigned short *screenpos(struct vc_data *vc, int offset, int viewed)
     295                 :            : {
     296                 :            :         unsigned short *p;
     297                 :            :         
     298                 :          0 :         if (!viewed)
     299                 :          0 :                 p = (unsigned short *)(vc->vc_origin + offset);
     300                 :          0 :         else if (!vc->vc_sw->con_screen_pos)
     301                 :          0 :                 p = (unsigned short *)(vc->vc_visible_origin + offset);
     302                 :            :         else
     303                 :          0 :                 p = vc->vc_sw->con_screen_pos(vc, offset);
     304                 :            :         return p;
     305                 :            : }
     306                 :            : 
     307                 :            : /* Called  from the keyboard irq path.. */
     308                 :          0 : static inline void scrolldelta(int lines)
     309                 :            : {
     310                 :            :         /* FIXME */
     311                 :            :         /* scrolldelta needs some kind of consistency lock, but the BKL was
     312                 :            :            and still is not protecting versus the scheduled back end */
     313                 :          0 :         scrollback_delta += lines;
     314                 :            :         schedule_console_callback();
     315                 :          0 : }
     316                 :            : 
     317                 :          3 : void schedule_console_callback(void)
     318                 :            : {
     319                 :            :         schedule_work(&console_work);
     320                 :          3 : }
     321                 :            : 
     322                 :            : /*
     323                 :            :  * Code to manage unicode-based screen buffers
     324                 :            :  */
     325                 :            : 
     326                 :            : #ifdef NO_VC_UNI_SCREEN
     327                 :            : /* this disables and optimizes related code away at compile time */
     328                 :            : #define get_vc_uniscr(vc) NULL
     329                 :            : #else
     330                 :            : #define get_vc_uniscr(vc) vc->vc_uni_screen
     331                 :            : #endif
     332                 :            : 
     333                 :            : #define VC_UNI_SCREEN_DEBUG 0
     334                 :            : 
     335                 :            : typedef uint32_t char32_t;
     336                 :            : 
     337                 :            : /*
     338                 :            :  * Our screen buffer is preceded by an array of line pointers so that
     339                 :            :  * scrolling only implies some pointer shuffling.
     340                 :            :  */
     341                 :            : struct uni_screen {
     342                 :            :         char32_t *lines[0];
     343                 :            : };
     344                 :            : 
     345                 :          0 : static struct uni_screen *vc_uniscr_alloc(unsigned int cols, unsigned int rows)
     346                 :            : {
     347                 :            :         struct uni_screen *uniscr;
     348                 :            :         void *p;
     349                 :            :         unsigned int memsize, i;
     350                 :            : 
     351                 :            :         /* allocate everything in one go */
     352                 :          0 :         memsize = cols * rows * sizeof(char32_t);
     353                 :          0 :         memsize += rows * sizeof(char32_t *);
     354                 :          0 :         p = vmalloc(memsize);
     355                 :          0 :         if (!p)
     356                 :            :                 return NULL;
     357                 :            : 
     358                 :            :         /* initial line pointers */
     359                 :            :         uniscr = p;
     360                 :          0 :         p = uniscr->lines + rows;
     361                 :          0 :         for (i = 0; i < rows; i++) {
     362                 :          0 :                 uniscr->lines[i] = p;
     363                 :          0 :                 p += cols * sizeof(char32_t);
     364                 :            :         }
     365                 :            :         return uniscr;
     366                 :            : }
     367                 :            : 
     368                 :            : static void vc_uniscr_free(struct uni_screen *uniscr)
     369                 :            : {
     370                 :          3 :         vfree(uniscr);
     371                 :            : }
     372                 :            : 
     373                 :            : static void vc_uniscr_set(struct vc_data *vc, struct uni_screen *new_uniscr)
     374                 :            : {
     375                 :          3 :         vc_uniscr_free(vc->vc_uni_screen);
     376                 :          3 :         vc->vc_uni_screen = new_uniscr;
     377                 :            : }
     378                 :            : 
     379                 :            : static void vc_uniscr_putc(struct vc_data *vc, char32_t uc)
     380                 :            : {
     381                 :          3 :         struct uni_screen *uniscr = get_vc_uniscr(vc);
     382                 :            : 
     383                 :          3 :         if (uniscr)
     384                 :          0 :                 uniscr->lines[vc->vc_y][vc->vc_x] = uc;
     385                 :            : }
     386                 :            : 
     387                 :          0 : static void vc_uniscr_insert(struct vc_data *vc, unsigned int nr)
     388                 :            : {
     389                 :          0 :         struct uni_screen *uniscr = get_vc_uniscr(vc);
     390                 :            : 
     391                 :          0 :         if (uniscr) {
     392                 :          0 :                 char32_t *ln = uniscr->lines[vc->vc_y];
     393                 :          0 :                 unsigned int x = vc->vc_x, cols = vc->vc_cols;
     394                 :            : 
     395                 :          0 :                 memmove(&ln[x + nr], &ln[x], (cols - x - nr) * sizeof(*ln));
     396                 :            :                 memset32(&ln[x], ' ', nr);
     397                 :            :         }
     398                 :          0 : }
     399                 :            : 
     400                 :          0 : static void vc_uniscr_delete(struct vc_data *vc, unsigned int nr)
     401                 :            : {
     402                 :          0 :         struct uni_screen *uniscr = get_vc_uniscr(vc);
     403                 :            : 
     404                 :          0 :         if (uniscr) {
     405                 :          0 :                 char32_t *ln = uniscr->lines[vc->vc_y];
     406                 :          0 :                 unsigned int x = vc->vc_x, cols = vc->vc_cols;
     407                 :            : 
     408                 :          0 :                 memcpy(&ln[x], &ln[x + nr], (cols - x - nr) * sizeof(*ln));
     409                 :          0 :                 memset32(&ln[cols - nr], ' ', nr);
     410                 :            :         }
     411                 :          0 : }
     412                 :            : 
     413                 :          3 : static void vc_uniscr_clear_line(struct vc_data *vc, unsigned int x,
     414                 :            :                                  unsigned int nr)
     415                 :            : {
     416                 :          3 :         struct uni_screen *uniscr = get_vc_uniscr(vc);
     417                 :            : 
     418                 :          3 :         if (uniscr) {
     419                 :          0 :                 char32_t *ln = uniscr->lines[vc->vc_y];
     420                 :            : 
     421                 :          0 :                 memset32(&ln[x], ' ', nr);
     422                 :            :         }
     423                 :          3 : }
     424                 :            : 
     425                 :          3 : static void vc_uniscr_clear_lines(struct vc_data *vc, unsigned int y,
     426                 :            :                                   unsigned int nr)
     427                 :            : {
     428                 :          3 :         struct uni_screen *uniscr = get_vc_uniscr(vc);
     429                 :            : 
     430                 :          3 :         if (uniscr) {
     431                 :          0 :                 unsigned int cols = vc->vc_cols;
     432                 :            : 
     433                 :          0 :                 while (nr--)
     434                 :          0 :                         memset32(uniscr->lines[y++], ' ', cols);
     435                 :            :         }
     436                 :          3 : }
     437                 :            : 
     438                 :          0 : static void vc_uniscr_scroll(struct vc_data *vc, unsigned int t, unsigned int b,
     439                 :            :                              enum con_scroll dir, unsigned int nr)
     440                 :            : {
     441                 :          0 :         struct uni_screen *uniscr = get_vc_uniscr(vc);
     442                 :            : 
     443                 :          0 :         if (uniscr) {
     444                 :            :                 unsigned int i, j, k, sz, d, clear;
     445                 :            : 
     446                 :          0 :                 sz = b - t;
     447                 :          0 :                 clear = b - nr;
     448                 :            :                 d = nr;
     449                 :          0 :                 if (dir == SM_DOWN) {
     450                 :            :                         clear = t;
     451                 :          0 :                         d = sz - nr;
     452                 :            :                 }
     453                 :          0 :                 for (i = 0; i < gcd(d, sz); i++) {
     454                 :          0 :                         char32_t *tmp = uniscr->lines[t + i];
     455                 :            :                         j = i;
     456                 :            :                         while (1) {
     457                 :          0 :                                 k = j + d;
     458                 :          0 :                                 if (k >= sz)
     459                 :          0 :                                         k -= sz;
     460                 :          0 :                                 if (k == i)
     461                 :            :                                         break;
     462                 :          0 :                                 uniscr->lines[t + j] = uniscr->lines[t + k];
     463                 :            :                                 j = k;
     464                 :          0 :                         }
     465                 :          0 :                         uniscr->lines[t + j] = tmp;
     466                 :            :                 }
     467                 :          0 :                 vc_uniscr_clear_lines(vc, clear, nr);
     468                 :            :         }
     469                 :          0 : }
     470                 :            : 
     471                 :          3 : static void vc_uniscr_copy_area(struct uni_screen *dst,
     472                 :            :                                 unsigned int dst_cols,
     473                 :            :                                 unsigned int dst_rows,
     474                 :            :                                 struct uni_screen *src,
     475                 :            :                                 unsigned int src_cols,
     476                 :            :                                 unsigned int src_top_row,
     477                 :            :                                 unsigned int src_bot_row)
     478                 :            : {
     479                 :            :         unsigned int dst_row = 0;
     480                 :            : 
     481                 :          3 :         if (!dst)
     482                 :          3 :                 return;
     483                 :            : 
     484                 :          0 :         while (src_top_row < src_bot_row) {
     485                 :          0 :                 char32_t *src_line = src->lines[src_top_row];
     486                 :          0 :                 char32_t *dst_line = dst->lines[dst_row];
     487                 :            : 
     488                 :          0 :                 memcpy(dst_line, src_line, src_cols * sizeof(char32_t));
     489                 :          0 :                 if (dst_cols - src_cols)
     490                 :          0 :                         memset32(dst_line + src_cols, ' ', dst_cols - src_cols);
     491                 :          0 :                 src_top_row++;
     492                 :          0 :                 dst_row++;
     493                 :            :         }
     494                 :          0 :         while (dst_row < dst_rows) {
     495                 :          0 :                 char32_t *dst_line = dst->lines[dst_row];
     496                 :            : 
     497                 :            :                 memset32(dst_line, ' ', dst_cols);
     498                 :          0 :                 dst_row++;
     499                 :            :         }
     500                 :            : }
     501                 :            : 
     502                 :            : /*
     503                 :            :  * Called from vcs_read() to make sure unicode screen retrieval is possible.
     504                 :            :  * This will initialize the unicode screen buffer if not already done.
     505                 :            :  * This returns 0 if OK, or a negative error code otherwise.
     506                 :            :  * In particular, -ENODATA is returned if the console is not in UTF-8 mode.
     507                 :            :  */
     508                 :          0 : int vc_uniscr_check(struct vc_data *vc)
     509                 :            : {
     510                 :            :         struct uni_screen *uniscr;
     511                 :            :         unsigned short *p;
     512                 :            :         int x, y, mask;
     513                 :            : 
     514                 :            :         if (__is_defined(NO_VC_UNI_SCREEN))
     515                 :            :                 return -EOPNOTSUPP;
     516                 :            : 
     517                 :          0 :         WARN_CONSOLE_UNLOCKED();
     518                 :            : 
     519                 :          0 :         if (!vc->vc_utf)
     520                 :            :                 return -ENODATA;
     521                 :            : 
     522                 :          0 :         if (vc->vc_uni_screen)
     523                 :            :                 return 0;
     524                 :            : 
     525                 :          0 :         uniscr = vc_uniscr_alloc(vc->vc_cols, vc->vc_rows);
     526                 :          0 :         if (!uniscr)
     527                 :            :                 return -ENOMEM;
     528                 :            : 
     529                 :            :         /*
     530                 :            :          * Let's populate it initially with (imperfect) reverse translation.
     531                 :            :          * This is the next best thing we can do short of having it enabled
     532                 :            :          * from the start even when no users rely on this functionality. True
     533                 :            :          * unicode content will be available after a complete screen refresh.
     534                 :            :          */
     535                 :          0 :         p = (unsigned short *)vc->vc_origin;
     536                 :          0 :         mask = vc->vc_hi_font_mask | 0xff;
     537                 :          0 :         for (y = 0; y < vc->vc_rows; y++) {
     538                 :          0 :                 char32_t *line = uniscr->lines[y];
     539                 :          0 :                 for (x = 0; x < vc->vc_cols; x++) {
     540                 :          0 :                         u16 glyph = scr_readw(p++) & mask;
     541                 :          0 :                         line[x] = inverse_translate(vc, glyph, true);
     542                 :            :                 }
     543                 :            :         }
     544                 :            : 
     545                 :          0 :         vc->vc_uni_screen = uniscr;
     546                 :          0 :         return 0;
     547                 :            : }
     548                 :            : 
     549                 :            : /*
     550                 :            :  * Called from vcs_read() to get the unicode data from the screen.
     551                 :            :  * This must be preceded by a successful call to vc_uniscr_check() once
     552                 :            :  * the console lock has been taken.
     553                 :            :  */
     554                 :          0 : void vc_uniscr_copy_line(struct vc_data *vc, void *dest, int viewed,
     555                 :            :                          unsigned int row, unsigned int col, unsigned int nr)
     556                 :            : {
     557                 :          0 :         struct uni_screen *uniscr = get_vc_uniscr(vc);
     558                 :          0 :         int offset = row * vc->vc_size_row + col * 2;
     559                 :            :         unsigned long pos;
     560                 :            : 
     561                 :          0 :         BUG_ON(!uniscr);
     562                 :            : 
     563                 :          0 :         pos = (unsigned long)screenpos(vc, offset, viewed);
     564                 :          0 :         if (pos >= vc->vc_origin && pos < vc->vc_scr_end) {
     565                 :            :                 /*
     566                 :            :                  * Desired position falls in the main screen buffer.
     567                 :            :                  * However the actual row/col might be different if
     568                 :            :                  * scrollback is active.
     569                 :            :                  */
     570                 :          0 :                 row = (pos - vc->vc_origin) / vc->vc_size_row;
     571                 :          0 :                 col = ((pos - vc->vc_origin) % vc->vc_size_row) / 2;
     572                 :          0 :                 memcpy(dest, &uniscr->lines[row][col], nr * sizeof(char32_t));
     573                 :            :         } else {
     574                 :            :                 /*
     575                 :            :                  * Scrollback is active. For now let's simply backtranslate
     576                 :            :                  * the screen glyphs until the unicode screen buffer does
     577                 :            :                  * synchronize with console display drivers for a scrollback
     578                 :            :                  * buffer of its own.
     579                 :            :                  */
     580                 :            :                 u16 *p = (u16 *)pos;
     581                 :          0 :                 int mask = vc->vc_hi_font_mask | 0xff;
     582                 :            :                 char32_t *uni_buf = dest;
     583                 :          0 :                 while (nr--) {
     584                 :          0 :                         u16 glyph = scr_readw(p++) & mask;
     585                 :          0 :                         *uni_buf++ = inverse_translate(vc, glyph, true);
     586                 :            :                 }
     587                 :            :         }
     588                 :          0 : }
     589                 :            : 
     590                 :            : /* this is for validation and debugging only */
     591                 :            : static void vc_uniscr_debug_check(struct vc_data *vc)
     592                 :            : {
     593                 :            :         struct uni_screen *uniscr = get_vc_uniscr(vc);
     594                 :            :         unsigned short *p;
     595                 :            :         int x, y, mask;
     596                 :            : 
     597                 :            :         if (!VC_UNI_SCREEN_DEBUG || !uniscr)
     598                 :            :                 return;
     599                 :            : 
     600                 :            :         WARN_CONSOLE_UNLOCKED();
     601                 :            : 
     602                 :            :         /*
     603                 :            :          * Make sure our unicode screen translates into the same glyphs
     604                 :            :          * as the actual screen. This is brutal indeed.
     605                 :            :          */
     606                 :            :         p = (unsigned short *)vc->vc_origin;
     607                 :            :         mask = vc->vc_hi_font_mask | 0xff;
     608                 :            :         for (y = 0; y < vc->vc_rows; y++) {
     609                 :            :                 char32_t *line = uniscr->lines[y];
     610                 :            :                 for (x = 0; x < vc->vc_cols; x++) {
     611                 :            :                         u16 glyph = scr_readw(p++) & mask;
     612                 :            :                         char32_t uc = line[x];
     613                 :            :                         int tc = conv_uni_to_pc(vc, uc);
     614                 :            :                         if (tc == -4)
     615                 :            :                                 tc = conv_uni_to_pc(vc, 0xfffd);
     616                 :            :                         if (tc == -4)
     617                 :            :                                 tc = conv_uni_to_pc(vc, '?');
     618                 :            :                         if (tc != glyph)
     619                 :            :                                 pr_err_ratelimited(
     620                 :            :                                         "%s: mismatch at %d,%d: glyph=%#x tc=%#x\n",
     621                 :            :                                         __func__, x, y, glyph, tc);
     622                 :            :                 }
     623                 :            :         }
     624                 :            : }
     625                 :            : 
     626                 :            : 
     627                 :          0 : static void con_scroll(struct vc_data *vc, unsigned int t, unsigned int b,
     628                 :            :                 enum con_scroll dir, unsigned int nr)
     629                 :            : {
     630                 :            :         u16 *clear, *d, *s;
     631                 :            : 
     632                 :          0 :         if (t + nr >= b)
     633                 :          0 :                 nr = b - t - 1;
     634                 :          0 :         if (b > vc->vc_rows || t >= b || nr < 1)
     635                 :            :                 return;
     636                 :          0 :         vc_uniscr_scroll(vc, t, b, dir, nr);
     637                 :          0 :         if (con_is_visible(vc) && vc->vc_sw->con_scroll(vc, t, b, dir, nr))
     638                 :            :                 return;
     639                 :            : 
     640                 :          0 :         s = clear = (u16 *)(vc->vc_origin + vc->vc_size_row * t);
     641                 :          0 :         d = (u16 *)(vc->vc_origin + vc->vc_size_row * (t + nr));
     642                 :            : 
     643                 :          0 :         if (dir == SM_UP) {
     644                 :          0 :                 clear = s + (b - t - nr) * vc->vc_cols;
     645                 :            :                 swap(s, d);
     646                 :            :         }
     647                 :          0 :         scr_memmovew(d, s, (b - t - nr) * vc->vc_size_row);
     648                 :          0 :         scr_memsetw(clear, vc->vc_video_erase_char, vc->vc_size_row * nr);
     649                 :            : }
     650                 :            : 
     651                 :          3 : static void do_update_region(struct vc_data *vc, unsigned long start, int count)
     652                 :            : {
     653                 :            :         unsigned int xx, yy, offset;
     654                 :            :         u16 *p;
     655                 :            : 
     656                 :          3 :         p = (u16 *) start;
     657                 :          3 :         if (!vc->vc_sw->con_getxy) {
     658                 :          3 :                 offset = (start - vc->vc_origin) / 2;
     659                 :          3 :                 xx = offset % vc->vc_cols;
     660                 :          3 :                 yy = offset / vc->vc_cols;
     661                 :            :         } else {
     662                 :            :                 int nxx, nyy;
     663                 :          3 :                 start = vc->vc_sw->con_getxy(vc, start, &nxx, &nyy);
     664                 :          3 :                 xx = nxx; yy = nyy;
     665                 :            :         }
     666                 :            :         for(;;) {
     667                 :          3 :                 u16 attrib = scr_readw(p) & 0xff00;
     668                 :          3 :                 int startx = xx;
     669                 :            :                 u16 *q = p;
     670                 :          3 :                 while (xx < vc->vc_cols && count) {
     671                 :          3 :                         if (attrib != (scr_readw(p) & 0xff00)) {
     672                 :          0 :                                 if (p > q)
     673                 :          0 :                                         vc->vc_sw->con_putcs(vc, q, p-q, yy, startx);
     674                 :          0 :                                 startx = xx;
     675                 :            :                                 q = p;
     676                 :          0 :                                 attrib = scr_readw(p) & 0xff00;
     677                 :            :                         }
     678                 :          3 :                         p++;
     679                 :          3 :                         xx++;
     680                 :          3 :                         count--;
     681                 :            :                 }
     682                 :          3 :                 if (p > q)
     683                 :          3 :                         vc->vc_sw->con_putcs(vc, q, p-q, yy, startx);
     684                 :          3 :                 if (!count)
     685                 :            :                         break;
     686                 :            :                 xx = 0;
     687                 :          3 :                 yy++;
     688                 :          3 :                 if (vc->vc_sw->con_getxy) {
     689                 :          3 :                         p = (u16 *)start;
     690                 :          3 :                         start = vc->vc_sw->con_getxy(vc, start, NULL, NULL);
     691                 :            :                 }
     692                 :            :         }
     693                 :          3 : }
     694                 :            : 
     695                 :          1 : void update_region(struct vc_data *vc, unsigned long start, int count)
     696                 :            : {
     697                 :          1 :         WARN_CONSOLE_UNLOCKED();
     698                 :            : 
     699                 :          1 :         if (con_should_update(vc)) {
     700                 :          1 :                 hide_cursor(vc);
     701                 :          1 :                 do_update_region(vc, start, count);
     702                 :          1 :                 set_cursor(vc);
     703                 :            :         }
     704                 :          1 : }
     705                 :            : 
     706                 :            : /* Structure of attributes is hardware-dependent */
     707                 :            : 
     708                 :          3 : static u8 build_attr(struct vc_data *vc, u8 _color, u8 _intensity, u8 _blink,
     709                 :            :     u8 _underline, u8 _reverse, u8 _italic)
     710                 :            : {
     711                 :          3 :         if (vc->vc_sw->con_build_attr)
     712                 :          0 :                 return vc->vc_sw->con_build_attr(vc, _color, _intensity,
     713                 :            :                        _blink, _underline, _reverse, _italic);
     714                 :            : 
     715                 :            : /*
     716                 :            :  * ++roman: I completely changed the attribute format for monochrome
     717                 :            :  * mode (!can_do_color). The formerly used MDA (monochrome display
     718                 :            :  * adapter) format didn't allow the combination of certain effects.
     719                 :            :  * Now the attribute is just a bit vector:
     720                 :            :  *  Bit 0..1: intensity (0..2)
     721                 :            :  *  Bit 2   : underline
     722                 :            :  *  Bit 3   : reverse
     723                 :            :  *  Bit 7   : blink
     724                 :            :  */
     725                 :            :         {
     726                 :            :         u8 a = _color;
     727                 :          3 :         if (!vc->vc_can_do_color)
     728                 :          0 :                 return _intensity |
     729                 :            :                        (_italic ? 2 : 0) |
     730                 :            :                        (_underline ? 4 : 0) |
     731                 :            :                        (_reverse ? 8 : 0) |
     732                 :            :                        (_blink ? 0x80 : 0);
     733                 :          3 :         if (_italic)
     734                 :          0 :                 a = (a & 0xF0) | vc->vc_itcolor;
     735                 :          3 :         else if (_underline)
     736                 :          0 :                 a = (a & 0xf0) | vc->vc_ulcolor;
     737                 :          3 :         else if (_intensity == 0)
     738                 :          0 :                 a = (a & 0xf0) | vc->vc_halfcolor;
     739                 :          3 :         if (_reverse)
     740                 :          0 :                 a = ((a) & 0x88) | ((((a) >> 4) | ((a) << 4)) & 0x77);
     741                 :          3 :         if (_blink)
     742                 :          0 :                 a ^= 0x80;
     743                 :          3 :         if (_intensity == 2)
     744                 :          3 :                 a ^= 0x08;
     745                 :          3 :         if (vc->vc_hi_font_mask == 0x100)
     746                 :          0 :                 a <<= 1;
     747                 :          3 :         return a;
     748                 :            :         }
     749                 :            : }
     750                 :            : 
     751                 :          3 : static void update_attr(struct vc_data *vc)
     752                 :            : {
     753                 :          3 :         vc->vc_attr = build_attr(vc, vc->vc_color, vc->vc_intensity,
     754                 :          3 :                       vc->vc_blink, vc->vc_underline,
     755                 :          3 :                       vc->vc_reverse ^ vc->vc_decscnm, vc->vc_italic);
     756                 :          3 :         vc->vc_video_erase_char = (build_attr(vc, vc->vc_color, 1, vc->vc_blink, 0, vc->vc_decscnm, 0) << 8) | ' ';
     757                 :          3 : }
     758                 :            : 
     759                 :            : /* Note: inverting the screen twice should revert to the original state */
     760                 :          0 : void invert_screen(struct vc_data *vc, int offset, int count, int viewed)
     761                 :            : {
     762                 :            :         unsigned short *p;
     763                 :            : 
     764                 :          0 :         WARN_CONSOLE_UNLOCKED();
     765                 :            : 
     766                 :          0 :         count /= 2;
     767                 :            :         p = screenpos(vc, offset, viewed);
     768                 :          0 :         if (vc->vc_sw->con_invert_region) {
     769                 :          0 :                 vc->vc_sw->con_invert_region(vc, p, count);
     770                 :            :         } else {
     771                 :            :                 u16 *q = p;
     772                 :            :                 int cnt = count;
     773                 :            :                 u16 a;
     774                 :            : 
     775                 :          0 :                 if (!vc->vc_can_do_color) {
     776                 :          0 :                         while (cnt--) {
     777                 :          0 :                             a = scr_readw(q);
     778                 :          0 :                             a ^= 0x0800;
     779                 :          0 :                             scr_writew(a, q);
     780                 :          0 :                             q++;
     781                 :            :                         }
     782                 :          0 :                 } else if (vc->vc_hi_font_mask == 0x100) {
     783                 :          0 :                         while (cnt--) {
     784                 :          0 :                                 a = scr_readw(q);
     785                 :          0 :                                 a = ((a) & 0x11ff) | (((a) & 0xe000) >> 4) | (((a) & 0x0e00) << 4);
     786                 :          0 :                                 scr_writew(a, q);
     787                 :          0 :                                 q++;
     788                 :            :                         }
     789                 :            :                 } else {
     790                 :          0 :                         while (cnt--) {
     791                 :          0 :                                 a = scr_readw(q);
     792                 :          0 :                                 a = ((a) & 0x88ff) | (((a) & 0x7000) >> 4) | (((a) & 0x0700) << 4);
     793                 :          0 :                                 scr_writew(a, q);
     794                 :          0 :                                 q++;
     795                 :            :                         }
     796                 :            :                 }
     797                 :            :         }
     798                 :            : 
     799                 :          0 :         if (con_should_update(vc))
     800                 :          0 :                 do_update_region(vc, (unsigned long) p, count);
     801                 :            :         notify_update(vc);
     802                 :          0 : }
     803                 :            : 
     804                 :            : /* used by selection: complement pointer position */
     805                 :          0 : void complement_pos(struct vc_data *vc, int offset)
     806                 :            : {
     807                 :            :         static int old_offset = -1;
     808                 :            :         static unsigned short old;
     809                 :            :         static unsigned short oldx, oldy;
     810                 :            : 
     811                 :          0 :         WARN_CONSOLE_UNLOCKED();
     812                 :            : 
     813                 :          0 :         if (old_offset != -1 && old_offset >= 0 &&
     814                 :          0 :             old_offset < vc->vc_screenbuf_size) {
     815                 :          0 :                 scr_writew(old, screenpos(vc, old_offset, 1));
     816                 :          0 :                 if (con_should_update(vc))
     817                 :          0 :                         vc->vc_sw->con_putc(vc, old, oldy, oldx);
     818                 :            :                 notify_update(vc);
     819                 :            :         }
     820                 :            : 
     821                 :          0 :         old_offset = offset;
     822                 :            : 
     823                 :          0 :         if (offset != -1 && offset >= 0 &&
     824                 :          0 :             offset < vc->vc_screenbuf_size) {
     825                 :            :                 unsigned short new;
     826                 :            :                 unsigned short *p;
     827                 :            :                 p = screenpos(vc, offset, 1);
     828                 :          0 :                 old = scr_readw(p);
     829                 :          0 :                 new = old ^ vc->vc_complement_mask;
     830                 :          0 :                 scr_writew(new, p);
     831                 :          0 :                 if (con_should_update(vc)) {
     832                 :          0 :                         oldx = (offset >> 1) % vc->vc_cols;
     833                 :          0 :                         oldy = (offset >> 1) / vc->vc_cols;
     834                 :          0 :                         vc->vc_sw->con_putc(vc, new, oldy, oldx);
     835                 :            :                 }
     836                 :            :                 notify_update(vc);
     837                 :            :         }
     838                 :          0 : }
     839                 :            : 
     840                 :          0 : static void insert_char(struct vc_data *vc, unsigned int nr)
     841                 :            : {
     842                 :          0 :         unsigned short *p = (unsigned short *) vc->vc_pos;
     843                 :            : 
     844                 :          0 :         vc_uniscr_insert(vc, nr);
     845                 :          0 :         scr_memmovew(p + nr, p, (vc->vc_cols - vc->vc_x - nr) * 2);
     846                 :          0 :         scr_memsetw(p, vc->vc_video_erase_char, nr * 2);
     847                 :          0 :         vc->vc_need_wrap = 0;
     848                 :          0 :         if (con_should_update(vc))
     849                 :          0 :                 do_update_region(vc, (unsigned long) p,
     850                 :          0 :                         vc->vc_cols - vc->vc_x);
     851                 :          0 : }
     852                 :            : 
     853                 :          0 : static void delete_char(struct vc_data *vc, unsigned int nr)
     854                 :            : {
     855                 :          0 :         unsigned short *p = (unsigned short *) vc->vc_pos;
     856                 :            : 
     857                 :          0 :         vc_uniscr_delete(vc, nr);
     858                 :          0 :         scr_memcpyw(p, p + nr, (vc->vc_cols - vc->vc_x - nr) * 2);
     859                 :          0 :         scr_memsetw(p + vc->vc_cols - vc->vc_x - nr, vc->vc_video_erase_char,
     860                 :            :                         nr * 2);
     861                 :          0 :         vc->vc_need_wrap = 0;
     862                 :          0 :         if (con_should_update(vc))
     863                 :          0 :                 do_update_region(vc, (unsigned long) p,
     864                 :          0 :                         vc->vc_cols - vc->vc_x);
     865                 :          0 : }
     866                 :            : 
     867                 :            : static int softcursor_original = -1;
     868                 :            : 
     869                 :          3 : static void add_softcursor(struct vc_data *vc)
     870                 :            : {
     871                 :          3 :         int i = scr_readw((u16 *) vc->vc_pos);
     872                 :          3 :         u32 type = vc->vc_cursor_type;
     873                 :            : 
     874                 :          3 :         if (! (type & 0x10)) return;
     875                 :          0 :         if (softcursor_original != -1) return;
     876                 :          0 :         softcursor_original = i;
     877                 :          0 :         i |= ((type >> 8) & 0xff00 );
     878                 :          0 :         i ^= ((type) & 0xff00 );
     879                 :          0 :         if ((type & 0x20) && ((softcursor_original & 0x7000) == (i & 0x7000))) i ^= 0x7000;
     880                 :          0 :         if ((type & 0x40) && ((i & 0x700) == ((i & 0x7000) >> 4))) i ^= 0x0700;
     881                 :          0 :         scr_writew(i, (u16 *) vc->vc_pos);
     882                 :          0 :         if (con_should_update(vc))
     883                 :          0 :                 vc->vc_sw->con_putc(vc, i, vc->vc_y, vc->vc_x);
     884                 :            : }
     885                 :            : 
     886                 :          3 : static void hide_softcursor(struct vc_data *vc)
     887                 :            : {
     888                 :          3 :         if (softcursor_original != -1) {
     889                 :          0 :                 scr_writew(softcursor_original, (u16 *)vc->vc_pos);
     890                 :          0 :                 if (con_should_update(vc))
     891                 :          0 :                         vc->vc_sw->con_putc(vc, softcursor_original,
     892                 :          0 :                                         vc->vc_y, vc->vc_x);
     893                 :          0 :                 softcursor_original = -1;
     894                 :            :         }
     895                 :          3 : }
     896                 :            : 
     897                 :          3 : static void hide_cursor(struct vc_data *vc)
     898                 :            : {
     899                 :          3 :         if (vc_is_sel(vc))
     900                 :          0 :                 clear_selection();
     901                 :            : 
     902                 :          3 :         vc->vc_sw->con_cursor(vc, CM_ERASE);
     903                 :          3 :         hide_softcursor(vc);
     904                 :          3 : }
     905                 :            : 
     906                 :          3 : static void set_cursor(struct vc_data *vc)
     907                 :            : {
     908                 :          3 :         if (!con_is_fg(vc) || console_blanked || vc->vc_mode == KD_GRAPHICS)
     909                 :          3 :                 return;
     910                 :          3 :         if (vc->vc_deccm) {
     911                 :          3 :                 if (vc_is_sel(vc))
     912                 :          0 :                         clear_selection();
     913                 :          3 :                 add_softcursor(vc);
     914                 :          3 :                 if ((vc->vc_cursor_type & 0x0f) != 1)
     915                 :          3 :                         vc->vc_sw->con_cursor(vc, CM_DRAW);
     916                 :            :         } else
     917                 :          0 :                 hide_cursor(vc);
     918                 :            : }
     919                 :            : 
     920                 :          3 : static void set_origin(struct vc_data *vc)
     921                 :            : {
     922                 :          3 :         WARN_CONSOLE_UNLOCKED();
     923                 :            : 
     924                 :          3 :         if (!con_is_visible(vc) ||
     925                 :          3 :             !vc->vc_sw->con_set_origin ||
     926                 :          3 :             !vc->vc_sw->con_set_origin(vc))
     927                 :          3 :                 vc->vc_origin = (unsigned long)vc->vc_screenbuf;
     928                 :          3 :         vc->vc_visible_origin = vc->vc_origin;
     929                 :          3 :         vc->vc_scr_end = vc->vc_origin + vc->vc_screenbuf_size;
     930                 :          3 :         vc->vc_pos = vc->vc_origin + vc->vc_size_row * vc->vc_y + 2 * vc->vc_x;
     931                 :          3 : }
     932                 :            : 
     933                 :          3 : static void save_screen(struct vc_data *vc)
     934                 :            : {
     935                 :          3 :         WARN_CONSOLE_UNLOCKED();
     936                 :            : 
     937                 :          3 :         if (vc->vc_sw->con_save_screen)
     938                 :          0 :                 vc->vc_sw->con_save_screen(vc);
     939                 :          3 : }
     940                 :            : 
     941                 :          0 : static void flush_scrollback(struct vc_data *vc)
     942                 :            : {
     943                 :          0 :         WARN_CONSOLE_UNLOCKED();
     944                 :            : 
     945                 :          0 :         set_origin(vc);
     946                 :          0 :         if (vc->vc_sw->con_flush_scrollback) {
     947                 :          0 :                 vc->vc_sw->con_flush_scrollback(vc);
     948                 :          0 :         } else if (con_is_visible(vc)) {
     949                 :            :                 /*
     950                 :            :                  * When no con_flush_scrollback method is provided then the
     951                 :            :                  * legacy way for flushing the scrollback buffer is to use
     952                 :            :                  * a side effect of the con_switch method. We do it only on
     953                 :            :                  * the foreground console as background consoles have no
     954                 :            :                  * scrollback buffers in that case and we obviously don't
     955                 :            :                  * want to switch to them.
     956                 :            :                  */
     957                 :          0 :                 hide_cursor(vc);
     958                 :          0 :                 vc->vc_sw->con_switch(vc);
     959                 :          0 :                 set_cursor(vc);
     960                 :            :         }
     961                 :          0 : }
     962                 :            : 
     963                 :            : /*
     964                 :            :  *      Redrawing of screen
     965                 :            :  */
     966                 :            : 
     967                 :          0 : void clear_buffer_attributes(struct vc_data *vc)
     968                 :            : {
     969                 :          0 :         unsigned short *p = (unsigned short *)vc->vc_origin;
     970                 :          0 :         int count = vc->vc_screenbuf_size / 2;
     971                 :          0 :         int mask = vc->vc_hi_font_mask | 0xff;
     972                 :            : 
     973                 :          0 :         for (; count > 0; count--, p++) {
     974                 :          0 :                 scr_writew((scr_readw(p)&mask) | (vc->vc_video_erase_char & ~mask), p);
     975                 :            :         }
     976                 :          0 : }
     977                 :            : 
     978                 :          3 : void redraw_screen(struct vc_data *vc, int is_switch)
     979                 :            : {
     980                 :            :         int redraw = 0;
     981                 :            : 
     982                 :          3 :         WARN_CONSOLE_UNLOCKED();
     983                 :            : 
     984                 :          3 :         if (!vc) {
     985                 :            :                 /* strange ... */
     986                 :            :                 /* printk("redraw_screen: tty %d not allocated ??\n", new_console+1); */
     987                 :            :                 return;
     988                 :            :         }
     989                 :            : 
     990                 :          3 :         if (is_switch) {
     991                 :          3 :                 struct vc_data *old_vc = vc_cons[fg_console].d;
     992                 :          3 :                 if (old_vc == vc)
     993                 :            :                         return;
     994                 :          3 :                 if (!con_is_visible(vc))
     995                 :            :                         redraw = 1;
     996                 :          3 :                 *vc->vc_display_fg = vc;
     997                 :          3 :                 fg_console = vc->vc_num;
     998                 :          3 :                 hide_cursor(old_vc);
     999                 :          3 :                 if (!con_is_visible(old_vc)) {
    1000                 :          3 :                         save_screen(old_vc);
    1001                 :          3 :                         set_origin(old_vc);
    1002                 :            :                 }
    1003                 :          3 :                 if (tty0dev)
    1004                 :          3 :                         sysfs_notify(&tty0dev->kobj, NULL, "active");
    1005                 :            :         } else {
    1006                 :          3 :                 hide_cursor(vc);
    1007                 :            :                 redraw = 1;
    1008                 :            :         }
    1009                 :            : 
    1010                 :          3 :         if (redraw) {
    1011                 :            :                 int update;
    1012                 :          3 :                 int old_was_color = vc->vc_can_do_color;
    1013                 :            : 
    1014                 :          3 :                 set_origin(vc);
    1015                 :          3 :                 update = vc->vc_sw->con_switch(vc);
    1016                 :          3 :                 set_palette(vc);
    1017                 :            :                 /*
    1018                 :            :                  * If console changed from mono<->color, the best we can do
    1019                 :            :                  * is to clear the buffer attributes. As it currently stands,
    1020                 :            :                  * rebuilding new attributes from the old buffer is not doable
    1021                 :            :                  * without overly complex code.
    1022                 :            :                  */
    1023                 :          3 :                 if (old_was_color != vc->vc_can_do_color) {
    1024                 :          0 :                         update_attr(vc);
    1025                 :          0 :                         clear_buffer_attributes(vc);
    1026                 :            :                 }
    1027                 :            : 
    1028                 :          3 :                 if (update && vc->vc_mode != KD_GRAPHICS)
    1029                 :          3 :                         do_update_region(vc, vc->vc_origin, vc->vc_screenbuf_size / 2);
    1030                 :            :         }
    1031                 :          3 :         set_cursor(vc);
    1032                 :          3 :         if (is_switch) {
    1033                 :            :                 set_leds();
    1034                 :          3 :                 compute_shiftstate();
    1035                 :            :                 notify_update(vc);
    1036                 :            :         }
    1037                 :            : }
    1038                 :            : 
    1039                 :            : /*
    1040                 :            :  *      Allocation, freeing and resizing of VTs.
    1041                 :            :  */
    1042                 :            : 
    1043                 :          3 : int vc_cons_allocated(unsigned int i)
    1044                 :            : {
    1045                 :          3 :         return (i < MAX_NR_CONSOLES && vc_cons[i].d);
    1046                 :            : }
    1047                 :            : 
    1048                 :          3 : static void visual_init(struct vc_data *vc, int num, int init)
    1049                 :            : {
    1050                 :            :         /* ++Geert: vc->vc_sw->con_init determines console size */
    1051                 :          3 :         if (vc->vc_sw)
    1052                 :          3 :                 module_put(vc->vc_sw->owner);
    1053                 :          3 :         vc->vc_sw = conswitchp;
    1054                 :            : #ifndef VT_SINGLE_DRIVER
    1055                 :          3 :         if (con_driver_map[num])
    1056                 :          3 :                 vc->vc_sw = con_driver_map[num];
    1057                 :            : #endif
    1058                 :          3 :         __module_get(vc->vc_sw->owner);
    1059                 :          3 :         vc->vc_num = num;
    1060                 :          3 :         vc->vc_display_fg = &master_display_fg;
    1061                 :          3 :         if (vc->vc_uni_pagedir_loc)
    1062                 :          3 :                 con_free_unimap(vc);
    1063                 :          3 :         vc->vc_uni_pagedir_loc = &vc->vc_uni_pagedir;
    1064                 :          3 :         vc->vc_uni_pagedir = NULL;
    1065                 :          3 :         vc->vc_hi_font_mask = 0;
    1066                 :          3 :         vc->vc_complement_mask = 0;
    1067                 :          3 :         vc->vc_can_do_color = 0;
    1068                 :          3 :         vc->vc_cur_blink_ms = DEFAULT_CURSOR_BLINK_MS;
    1069                 :          3 :         vc->vc_sw->con_init(vc, init);
    1070                 :          3 :         if (!vc->vc_complement_mask)
    1071                 :          3 :                 vc->vc_complement_mask = vc->vc_can_do_color ? 0x7700 : 0x0800;
    1072                 :          3 :         vc->vc_s_complement_mask = vc->vc_complement_mask;
    1073                 :          3 :         vc->vc_size_row = vc->vc_cols << 1;
    1074                 :          3 :         vc->vc_screenbuf_size = vc->vc_rows * vc->vc_size_row;
    1075                 :          3 : }
    1076                 :            : 
    1077                 :            : 
    1078                 :          0 : static void visual_deinit(struct vc_data *vc)
    1079                 :            : {
    1080                 :          0 :         vc->vc_sw->con_deinit(vc);
    1081                 :          0 :         module_put(vc->vc_sw->owner);
    1082                 :          0 : }
    1083                 :            : 
    1084                 :          0 : static void vc_port_destruct(struct tty_port *port)
    1085                 :            : {
    1086                 :            :         struct vc_data *vc = container_of(port, struct vc_data, port);
    1087                 :            : 
    1088                 :          0 :         kfree(vc);
    1089                 :          0 : }
    1090                 :            : 
    1091                 :            : static const struct tty_port_operations vc_port_ops = {
    1092                 :            :         .destruct = vc_port_destruct,
    1093                 :            : };
    1094                 :            : 
    1095                 :            : /*
    1096                 :            :  * Change # of rows and columns (0 means unchanged/the size of fg_console)
    1097                 :            :  * [this is to be used together with some user program
    1098                 :            :  * like resize that changes the hardware videomode]
    1099                 :            :  */
    1100                 :            : #define VC_MAXCOL (32767)
    1101                 :            : #define VC_MAXROW (32767)
    1102                 :            : 
    1103                 :          3 : int vc_allocate(unsigned int currcons)  /* return 0 on success */
    1104                 :            : {
    1105                 :            :         struct vt_notifier_param param;
    1106                 :            :         struct vc_data *vc;
    1107                 :            :         int err;
    1108                 :            : 
    1109                 :          3 :         WARN_CONSOLE_UNLOCKED();
    1110                 :            : 
    1111                 :          3 :         if (currcons >= MAX_NR_CONSOLES)
    1112                 :            :                 return -ENXIO;
    1113                 :            : 
    1114                 :          3 :         if (vc_cons[currcons].d)
    1115                 :            :                 return 0;
    1116                 :            : 
    1117                 :            :         /* due to the granularity of kmalloc, we waste some memory here */
    1118                 :            :         /* the alloc is done in two steps, to optimize the common situation
    1119                 :            :            of a 25x80 console (structsize=216, screenbuf_size=4000) */
    1120                 :            :         /* although the numbers above are not valid since long ago, the
    1121                 :            :            point is still up-to-date and the comment still has its value
    1122                 :            :            even if only as a historical artifact.  --mj, July 1998 */
    1123                 :          3 :         param.vc = vc = kzalloc(sizeof(struct vc_data), GFP_KERNEL);
    1124                 :          3 :         if (!vc)
    1125                 :            :                 return -ENOMEM;
    1126                 :            : 
    1127                 :          3 :         vc_cons[currcons].d = vc;
    1128                 :          3 :         tty_port_init(&vc->port);
    1129                 :          3 :         vc->port.ops = &vc_port_ops;
    1130                 :          3 :         INIT_WORK(&vc_cons[currcons].SAK_work, vc_SAK);
    1131                 :            : 
    1132                 :          3 :         visual_init(vc, currcons, 1);
    1133                 :            : 
    1134                 :          3 :         if (!*vc->vc_uni_pagedir_loc)
    1135                 :          0 :                 con_set_default_unimap(vc);
    1136                 :            : 
    1137                 :            :         err = -EINVAL;
    1138                 :          3 :         if (vc->vc_cols > VC_MAXCOL || vc->vc_rows > VC_MAXROW ||
    1139                 :          3 :             vc->vc_screenbuf_size > KMALLOC_MAX_SIZE || !vc->vc_screenbuf_size)
    1140                 :            :                 goto err_free;
    1141                 :            :         err = -ENOMEM;
    1142                 :          3 :         vc->vc_screenbuf = kzalloc(vc->vc_screenbuf_size, GFP_KERNEL);
    1143                 :          3 :         if (!vc->vc_screenbuf)
    1144                 :            :                 goto err_free;
    1145                 :            : 
    1146                 :            :         /* If no drivers have overridden us and the user didn't pass a
    1147                 :            :            boot option, default to displaying the cursor */
    1148                 :          3 :         if (global_cursor_default == -1)
    1149                 :          3 :                 global_cursor_default = 1;
    1150                 :            : 
    1151                 :          3 :         vc_init(vc, vc->vc_rows, vc->vc_cols, 1);
    1152                 :          3 :         vcs_make_sysfs(currcons);
    1153                 :          3 :         atomic_notifier_call_chain(&vt_notifier_list, VT_ALLOCATE, &param);
    1154                 :            : 
    1155                 :          3 :         return 0;
    1156                 :            : err_free:
    1157                 :          0 :         visual_deinit(vc);
    1158                 :          0 :         kfree(vc);
    1159                 :          0 :         vc_cons[currcons].d = NULL;
    1160                 :          0 :         return err;
    1161                 :            : }
    1162                 :            : 
    1163                 :            : static inline int resize_screen(struct vc_data *vc, int width, int height,
    1164                 :            :                                 int user)
    1165                 :            : {
    1166                 :            :         /* Resizes the resolution of the display adapater */
    1167                 :            :         int err = 0;
    1168                 :            : 
    1169                 :          3 :         if (vc->vc_mode != KD_GRAPHICS && vc->vc_sw->con_resize)
    1170                 :          0 :                 err = vc->vc_sw->con_resize(vc, width, height, user);
    1171                 :            : 
    1172                 :            :         return err;
    1173                 :            : }
    1174                 :            : 
    1175                 :            : /**
    1176                 :            :  *      vc_do_resize    -       resizing method for the tty
    1177                 :            :  *      @tty: tty being resized
    1178                 :            :  *      @real_tty: real tty (different to tty if a pty/tty pair)
    1179                 :            :  *      @vc: virtual console private data
    1180                 :            :  *      @cols: columns
    1181                 :            :  *      @lines: lines
    1182                 :            :  *
    1183                 :            :  *      Resize a virtual console, clipping according to the actual constraints.
    1184                 :            :  *      If the caller passes a tty structure then update the termios winsize
    1185                 :            :  *      information and perform any necessary signal handling.
    1186                 :            :  *
    1187                 :            :  *      Caller must hold the console semaphore. Takes the termios rwsem and
    1188                 :            :  *      ctrl_lock of the tty IFF a tty is passed.
    1189                 :            :  */
    1190                 :            : 
    1191                 :          3 : static int vc_do_resize(struct tty_struct *tty, struct vc_data *vc,
    1192                 :            :                                 unsigned int cols, unsigned int lines)
    1193                 :            : {
    1194                 :            :         unsigned long old_origin, new_origin, new_scr_end, rlth, rrem, err = 0;
    1195                 :            :         unsigned long end;
    1196                 :            :         unsigned int old_rows, old_row_size, first_copied_row;
    1197                 :            :         unsigned int new_cols, new_rows, new_row_size, new_screen_size;
    1198                 :            :         unsigned int user;
    1199                 :            :         unsigned short *newscreen;
    1200                 :            :         struct uni_screen *new_uniscr = NULL;
    1201                 :            : 
    1202                 :          3 :         WARN_CONSOLE_UNLOCKED();
    1203                 :            : 
    1204                 :          3 :         if (!vc)
    1205                 :            :                 return -ENXIO;
    1206                 :            : 
    1207                 :          3 :         user = vc->vc_resize_user;
    1208                 :          3 :         vc->vc_resize_user = 0;
    1209                 :            : 
    1210                 :          3 :         if (cols > VC_MAXCOL || lines > VC_MAXROW)
    1211                 :            :                 return -EINVAL;
    1212                 :            : 
    1213                 :          3 :         new_cols = (cols ? cols : vc->vc_cols);
    1214                 :          3 :         new_rows = (lines ? lines : vc->vc_rows);
    1215                 :          3 :         new_row_size = new_cols << 1;
    1216                 :          3 :         new_screen_size = new_row_size * new_rows;
    1217                 :            : 
    1218                 :          3 :         if (new_cols == vc->vc_cols && new_rows == vc->vc_rows)
    1219                 :            :                 return 0;
    1220                 :            : 
    1221                 :          3 :         if (new_screen_size > KMALLOC_MAX_SIZE || !new_screen_size)
    1222                 :            :                 return -EINVAL;
    1223                 :          3 :         newscreen = kzalloc(new_screen_size, GFP_USER);
    1224                 :          3 :         if (!newscreen)
    1225                 :            :                 return -ENOMEM;
    1226                 :            : 
    1227                 :          3 :         if (get_vc_uniscr(vc)) {
    1228                 :          0 :                 new_uniscr = vc_uniscr_alloc(new_cols, new_rows);
    1229                 :          0 :                 if (!new_uniscr) {
    1230                 :          0 :                         kfree(newscreen);
    1231                 :          0 :                         return -ENOMEM;
    1232                 :            :                 }
    1233                 :            :         }
    1234                 :            : 
    1235                 :          3 :         if (vc_is_sel(vc))
    1236                 :          0 :                 clear_selection();
    1237                 :            : 
    1238                 :          3 :         old_rows = vc->vc_rows;
    1239                 :          3 :         old_row_size = vc->vc_size_row;
    1240                 :            : 
    1241                 :          3 :         err = resize_screen(vc, new_cols, new_rows, user);
    1242                 :          3 :         if (err) {
    1243                 :          0 :                 kfree(newscreen);
    1244                 :            :                 vc_uniscr_free(new_uniscr);
    1245                 :          0 :                 return err;
    1246                 :            :         }
    1247                 :            : 
    1248                 :          3 :         vc->vc_rows = new_rows;
    1249                 :          3 :         vc->vc_cols = new_cols;
    1250                 :          3 :         vc->vc_size_row = new_row_size;
    1251                 :          3 :         vc->vc_screenbuf_size = new_screen_size;
    1252                 :            : 
    1253                 :          3 :         rlth = min(old_row_size, new_row_size);
    1254                 :          3 :         rrem = new_row_size - rlth;
    1255                 :          3 :         old_origin = vc->vc_origin;
    1256                 :          3 :         new_origin = (long) newscreen;
    1257                 :          3 :         new_scr_end = new_origin + new_screen_size;
    1258                 :            : 
    1259                 :          3 :         if (vc->vc_y > new_rows) {
    1260                 :          0 :                 if (old_rows - vc->vc_y < new_rows) {
    1261                 :            :                         /*
    1262                 :            :                          * Cursor near the bottom, copy contents from the
    1263                 :            :                          * bottom of buffer
    1264                 :            :                          */
    1265                 :          0 :                         first_copied_row = (old_rows - new_rows);
    1266                 :            :                 } else {
    1267                 :            :                         /*
    1268                 :            :                          * Cursor is in no man's land, copy 1/2 screenful
    1269                 :            :                          * from the top and bottom of cursor position
    1270                 :            :                          */
    1271                 :          0 :                         first_copied_row = (vc->vc_y - new_rows/2);
    1272                 :            :                 }
    1273                 :          0 :                 old_origin += first_copied_row * old_row_size;
    1274                 :            :         } else
    1275                 :            :                 first_copied_row = 0;
    1276                 :          3 :         end = old_origin + old_row_size * min(old_rows, new_rows);
    1277                 :            : 
    1278                 :          3 :         vc_uniscr_copy_area(new_uniscr, new_cols, new_rows,
    1279                 :          3 :                             get_vc_uniscr(vc), rlth/2, first_copied_row,
    1280                 :            :                             min(old_rows, new_rows));
    1281                 :            :         vc_uniscr_set(vc, new_uniscr);
    1282                 :            : 
    1283                 :          3 :         update_attr(vc);
    1284                 :            : 
    1285                 :          3 :         while (old_origin < end) {
    1286                 :          3 :                 scr_memcpyw((unsigned short *) new_origin,
    1287                 :            :                             (unsigned short *) old_origin, rlth);
    1288                 :          3 :                 if (rrem)
    1289                 :          3 :                         scr_memsetw((void *)(new_origin + rlth),
    1290                 :            :                                     vc->vc_video_erase_char, rrem);
    1291                 :          3 :                 old_origin += old_row_size;
    1292                 :          3 :                 new_origin += new_row_size;
    1293                 :            :         }
    1294                 :          3 :         if (new_scr_end > new_origin)
    1295                 :          2 :                 scr_memsetw((void *)new_origin, vc->vc_video_erase_char,
    1296                 :          2 :                             new_scr_end - new_origin);
    1297                 :          3 :         kfree(vc->vc_screenbuf);
    1298                 :          3 :         vc->vc_screenbuf = newscreen;
    1299                 :          3 :         vc->vc_screenbuf_size = new_screen_size;
    1300                 :          3 :         set_origin(vc);
    1301                 :            : 
    1302                 :            :         /* do part of a reset_terminal() */
    1303                 :          3 :         vc->vc_top = 0;
    1304                 :          3 :         vc->vc_bottom = vc->vc_rows;
    1305                 :          3 :         gotoxy(vc, vc->vc_x, vc->vc_y);
    1306                 :            :         save_cur(vc);
    1307                 :            : 
    1308                 :          3 :         if (tty) {
    1309                 :            :                 /* Rewrite the requested winsize data with the actual
    1310                 :            :                    resulting sizes */
    1311                 :            :                 struct winsize ws;
    1312                 :          0 :                 memset(&ws, 0, sizeof(ws));
    1313                 :          0 :                 ws.ws_row = vc->vc_rows;
    1314                 :          0 :                 ws.ws_col = vc->vc_cols;
    1315                 :          0 :                 ws.ws_ypixel = vc->vc_scan_lines;
    1316                 :          0 :                 tty_do_resize(tty, &ws);
    1317                 :            :         }
    1318                 :            : 
    1319                 :          3 :         if (con_is_visible(vc))
    1320                 :          3 :                 update_screen(vc);
    1321                 :          3 :         vt_event_post(VT_EVENT_RESIZE, vc->vc_num, vc->vc_num);
    1322                 :            :         notify_update(vc);
    1323                 :          3 :         return err;
    1324                 :            : }
    1325                 :            : 
    1326                 :            : /**
    1327                 :            :  *      vc_resize               -       resize a VT
    1328                 :            :  *      @vc: virtual console
    1329                 :            :  *      @cols: columns
    1330                 :            :  *      @rows: rows
    1331                 :            :  *
    1332                 :            :  *      Resize a virtual console as seen from the console end of things. We
    1333                 :            :  *      use the common vc_do_resize methods to update the structures. The
    1334                 :            :  *      caller must hold the console sem to protect console internals and
    1335                 :            :  *      vc->port.tty
    1336                 :            :  */
    1337                 :            : 
    1338                 :          3 : int vc_resize(struct vc_data *vc, unsigned int cols, unsigned int rows)
    1339                 :            : {
    1340                 :          3 :         return vc_do_resize(vc->port.tty, vc, cols, rows);
    1341                 :            : }
    1342                 :            : 
    1343                 :            : /**
    1344                 :            :  *      vt_resize               -       resize a VT
    1345                 :            :  *      @tty: tty to resize
    1346                 :            :  *      @ws: winsize attributes
    1347                 :            :  *
    1348                 :            :  *      Resize a virtual terminal. This is called by the tty layer as we
    1349                 :            :  *      register our own handler for resizing. The mutual helper does all
    1350                 :            :  *      the actual work.
    1351                 :            :  *
    1352                 :            :  *      Takes the console sem and the called methods then take the tty
    1353                 :            :  *      termios_rwsem and the tty ctrl_lock in that order.
    1354                 :            :  */
    1355                 :          3 : static int vt_resize(struct tty_struct *tty, struct winsize *ws)
    1356                 :            : {
    1357                 :          3 :         struct vc_data *vc = tty->driver_data;
    1358                 :            :         int ret;
    1359                 :            : 
    1360                 :          3 :         console_lock();
    1361                 :          3 :         ret = vc_do_resize(tty, vc, ws->ws_col, ws->ws_row);
    1362                 :          3 :         console_unlock();
    1363                 :          3 :         return ret;
    1364                 :            : }
    1365                 :            : 
    1366                 :          0 : struct vc_data *vc_deallocate(unsigned int currcons)
    1367                 :            : {
    1368                 :            :         struct vc_data *vc = NULL;
    1369                 :            : 
    1370                 :          0 :         WARN_CONSOLE_UNLOCKED();
    1371                 :            : 
    1372                 :          0 :         if (vc_cons_allocated(currcons)) {
    1373                 :            :                 struct vt_notifier_param param;
    1374                 :            : 
    1375                 :          0 :                 param.vc = vc = vc_cons[currcons].d;
    1376                 :          0 :                 atomic_notifier_call_chain(&vt_notifier_list, VT_DEALLOCATE, &param);
    1377                 :          0 :                 vcs_remove_sysfs(currcons);
    1378                 :          0 :                 visual_deinit(vc);
    1379                 :          0 :                 put_pid(vc->vt_pid);
    1380                 :            :                 vc_uniscr_set(vc, NULL);
    1381                 :          0 :                 kfree(vc->vc_screenbuf);
    1382                 :          0 :                 vc_cons[currcons].d = NULL;
    1383                 :            :         }
    1384                 :          0 :         return vc;
    1385                 :            : }
    1386                 :            : 
    1387                 :            : /*
    1388                 :            :  *      VT102 emulator
    1389                 :            :  */
    1390                 :            : 
    1391                 :            : enum { EPecma = 0, EPdec, EPeq, EPgt, EPlt};
    1392                 :            : 
    1393                 :            : #define set_kbd(vc, x)  vt_set_kbd_mode_bit((vc)->vc_num, (x))
    1394                 :            : #define clr_kbd(vc, x)  vt_clr_kbd_mode_bit((vc)->vc_num, (x))
    1395                 :            : #define is_kbd(vc, x)   vt_get_kbd_mode_bit((vc)->vc_num, (x))
    1396                 :            : 
    1397                 :            : #define decarm          VC_REPEAT
    1398                 :            : #define decckm          VC_CKMODE
    1399                 :            : #define kbdapplic       VC_APPLIC
    1400                 :            : #define lnm             VC_CRLF
    1401                 :            : 
    1402                 :            : /*
    1403                 :            :  * this is what the terminal answers to a ESC-Z or csi0c query.
    1404                 :            :  */
    1405                 :            : #define VT100ID "\033[?1;2c"
    1406                 :            : #define VT102ID "\033[?6c"
    1407                 :            : 
    1408                 :            : const unsigned char color_table[] = { 0, 4, 2, 6, 1, 5, 3, 7,
    1409                 :            :                                        8,12,10,14, 9,13,11,15 };
    1410                 :            : 
    1411                 :            : /* the default colour table, for VGA+ colour systems */
    1412                 :            : unsigned char default_red[] = {
    1413                 :            :         0x00, 0xaa, 0x00, 0xaa, 0x00, 0xaa, 0x00, 0xaa,
    1414                 :            :         0x55, 0xff, 0x55, 0xff, 0x55, 0xff, 0x55, 0xff
    1415                 :            : };
    1416                 :            : module_param_array(default_red, byte, NULL, S_IRUGO | S_IWUSR);
    1417                 :            : 
    1418                 :            : unsigned char default_grn[] = {
    1419                 :            :         0x00, 0x00, 0xaa, 0x55, 0x00, 0x00, 0xaa, 0xaa,
    1420                 :            :         0x55, 0x55, 0xff, 0xff, 0x55, 0x55, 0xff, 0xff
    1421                 :            : };
    1422                 :            : module_param_array(default_grn, byte, NULL, S_IRUGO | S_IWUSR);
    1423                 :            : 
    1424                 :            : unsigned char default_blu[] = {
    1425                 :            :         0x00, 0x00, 0x00, 0x00, 0xaa, 0xaa, 0xaa, 0xaa,
    1426                 :            :         0x55, 0x55, 0x55, 0x55, 0xff, 0xff, 0xff, 0xff
    1427                 :            : };
    1428                 :            : module_param_array(default_blu, byte, NULL, S_IRUGO | S_IWUSR);
    1429                 :            : 
    1430                 :            : /*
    1431                 :            :  * gotoxy() must verify all boundaries, because the arguments
    1432                 :            :  * might also be negative. If the given position is out of
    1433                 :            :  * bounds, the cursor is placed at the nearest margin.
    1434                 :            :  */
    1435                 :          3 : static void gotoxy(struct vc_data *vc, int new_x, int new_y)
    1436                 :            : {
    1437                 :            :         int min_y, max_y;
    1438                 :            : 
    1439                 :          3 :         if (new_x < 0)
    1440                 :          0 :                 vc->vc_x = 0;
    1441                 :            :         else {
    1442                 :          3 :                 if (new_x >= vc->vc_cols)
    1443                 :          0 :                         vc->vc_x = vc->vc_cols - 1;
    1444                 :            :                 else
    1445                 :          3 :                         vc->vc_x = new_x;
    1446                 :            :         }
    1447                 :            : 
    1448                 :          3 :         if (vc->vc_decom) {
    1449                 :          0 :                 min_y = vc->vc_top;
    1450                 :          0 :                 max_y = vc->vc_bottom;
    1451                 :            :         } else {
    1452                 :            :                 min_y = 0;
    1453                 :          3 :                 max_y = vc->vc_rows;
    1454                 :            :         }
    1455                 :          3 :         if (new_y < min_y)
    1456                 :          0 :                 vc->vc_y = min_y;
    1457                 :          3 :         else if (new_y >= max_y)
    1458                 :          0 :                 vc->vc_y = max_y - 1;
    1459                 :            :         else
    1460                 :          3 :                 vc->vc_y = new_y;
    1461                 :          3 :         vc->vc_pos = vc->vc_origin + vc->vc_y * vc->vc_size_row + (vc->vc_x<<1);
    1462                 :          3 :         vc->vc_need_wrap = 0;
    1463                 :          3 : }
    1464                 :            : 
    1465                 :            : /* for absolute user moves, when decom is set */
    1466                 :            : static void gotoxay(struct vc_data *vc, int new_x, int new_y)
    1467                 :            : {
    1468                 :          0 :         gotoxy(vc, new_x, vc->vc_decom ? (vc->vc_top + new_y) : new_y);
    1469                 :            : }
    1470                 :            : 
    1471                 :          0 : void scrollback(struct vc_data *vc)
    1472                 :            : {
    1473                 :          0 :         scrolldelta(-(vc->vc_rows / 2));
    1474                 :          0 : }
    1475                 :            : 
    1476                 :          0 : void scrollfront(struct vc_data *vc, int lines)
    1477                 :            : {
    1478                 :          0 :         if (!lines)
    1479                 :          0 :                 lines = vc->vc_rows / 2;
    1480                 :          0 :         scrolldelta(lines);
    1481                 :          0 : }
    1482                 :            : 
    1483                 :          3 : static void lf(struct vc_data *vc)
    1484                 :            : {
    1485                 :            :         /* don't scroll if above bottom of scrolling region, or
    1486                 :            :          * if below scrolling region
    1487                 :            :          */
    1488                 :          3 :         if (vc->vc_y + 1 == vc->vc_bottom)
    1489                 :          0 :                 con_scroll(vc, vc->vc_top, vc->vc_bottom, SM_UP, 1);
    1490                 :          3 :         else if (vc->vc_y < vc->vc_rows - 1) {
    1491                 :          3 :                 vc->vc_y++;
    1492                 :          3 :                 vc->vc_pos += vc->vc_size_row;
    1493                 :            :         }
    1494                 :          3 :         vc->vc_need_wrap = 0;
    1495                 :            :         notify_write(vc, '\n');
    1496                 :          3 : }
    1497                 :            : 
    1498                 :          0 : static void ri(struct vc_data *vc)
    1499                 :            : {
    1500                 :            :         /* don't scroll if below top of scrolling region, or
    1501                 :            :          * if above scrolling region
    1502                 :            :          */
    1503                 :          0 :         if (vc->vc_y == vc->vc_top)
    1504                 :          0 :                 con_scroll(vc, vc->vc_top, vc->vc_bottom, SM_DOWN, 1);
    1505                 :          0 :         else if (vc->vc_y > 0) {
    1506                 :          0 :                 vc->vc_y--;
    1507                 :          0 :                 vc->vc_pos -= vc->vc_size_row;
    1508                 :            :         }
    1509                 :          0 :         vc->vc_need_wrap = 0;
    1510                 :          0 : }
    1511                 :            : 
    1512                 :          3 : static inline void cr(struct vc_data *vc)
    1513                 :            : {
    1514                 :          3 :         vc->vc_pos -= vc->vc_x << 1;
    1515                 :          3 :         vc->vc_need_wrap = vc->vc_x = 0;
    1516                 :            :         notify_write(vc, '\r');
    1517                 :          3 : }
    1518                 :            : 
    1519                 :          0 : static inline void bs(struct vc_data *vc)
    1520                 :            : {
    1521                 :          0 :         if (vc->vc_x) {
    1522                 :          0 :                 vc->vc_pos -= 2;
    1523                 :          0 :                 vc->vc_x--;
    1524                 :          0 :                 vc->vc_need_wrap = 0;
    1525                 :            :                 notify_write(vc, '\b');
    1526                 :            :         }
    1527                 :          0 : }
    1528                 :            : 
    1529                 :            : static inline void del(struct vc_data *vc)
    1530                 :            : {
    1531                 :            :         /* ignored */
    1532                 :            : }
    1533                 :            : 
    1534                 :          3 : static void csi_J(struct vc_data *vc, int vpar)
    1535                 :            : {
    1536                 :            :         unsigned int count;
    1537                 :            :         unsigned short * start;
    1538                 :            : 
    1539                 :          3 :         switch (vpar) {
    1540                 :            :                 case 0: /* erase from cursor to end of display */
    1541                 :          3 :                         vc_uniscr_clear_line(vc, vc->vc_x,
    1542                 :          3 :                                              vc->vc_cols - vc->vc_x);
    1543                 :          3 :                         vc_uniscr_clear_lines(vc, vc->vc_y + 1,
    1544                 :          3 :                                               vc->vc_rows - vc->vc_y - 1);
    1545                 :          3 :                         count = (vc->vc_scr_end - vc->vc_pos) >> 1;
    1546                 :          3 :                         start = (unsigned short *)vc->vc_pos;
    1547                 :          3 :                         break;
    1548                 :            :                 case 1: /* erase from start to cursor */
    1549                 :          0 :                         vc_uniscr_clear_line(vc, 0, vc->vc_x + 1);
    1550                 :          0 :                         vc_uniscr_clear_lines(vc, 0, vc->vc_y);
    1551                 :          0 :                         count = ((vc->vc_pos - vc->vc_origin) >> 1) + 1;
    1552                 :          0 :                         start = (unsigned short *)vc->vc_origin;
    1553                 :          0 :                         break;
    1554                 :            :                 case 3: /* include scrollback */
    1555                 :          0 :                         flush_scrollback(vc);
    1556                 :            :                         /* fallthrough */
    1557                 :            :                 case 2: /* erase whole display */
    1558                 :          3 :                         vc_uniscr_clear_lines(vc, 0, vc->vc_rows);
    1559                 :          3 :                         count = vc->vc_cols * vc->vc_rows;
    1560                 :          3 :                         start = (unsigned short *)vc->vc_origin;
    1561                 :          3 :                         break;
    1562                 :            :                 default:
    1563                 :          3 :                         return;
    1564                 :            :         }
    1565                 :          3 :         scr_memsetw(start, vc->vc_video_erase_char, 2 * count);
    1566                 :          3 :         if (con_should_update(vc))
    1567                 :          3 :                 do_update_region(vc, (unsigned long) start, count);
    1568                 :          3 :         vc->vc_need_wrap = 0;
    1569                 :            : }
    1570                 :            : 
    1571                 :          0 : static void csi_K(struct vc_data *vc, int vpar)
    1572                 :            : {
    1573                 :            :         unsigned int count;
    1574                 :          0 :         unsigned short *start = (unsigned short *)vc->vc_pos;
    1575                 :            :         int offset;
    1576                 :            : 
    1577                 :          0 :         switch (vpar) {
    1578                 :            :                 case 0: /* erase from cursor to end of line */
    1579                 :            :                         offset = 0;
    1580                 :          0 :                         count = vc->vc_cols - vc->vc_x;
    1581                 :          0 :                         break;
    1582                 :            :                 case 1: /* erase from start of line to cursor */
    1583                 :          0 :                         offset = -vc->vc_x;
    1584                 :          0 :                         count = vc->vc_x + 1;
    1585                 :          0 :                         break;
    1586                 :            :                 case 2: /* erase whole line */
    1587                 :          0 :                         offset = -vc->vc_x;
    1588                 :          0 :                         count = vc->vc_cols;
    1589                 :          0 :                         break;
    1590                 :            :                 default:
    1591                 :          0 :                         return;
    1592                 :            :         }
    1593                 :          0 :         vc_uniscr_clear_line(vc, vc->vc_x + offset, count);
    1594                 :          0 :         scr_memsetw(start + offset, vc->vc_video_erase_char, 2 * count);
    1595                 :          0 :         vc->vc_need_wrap = 0;
    1596                 :          0 :         if (con_should_update(vc))
    1597                 :          0 :                 do_update_region(vc, (unsigned long)(start + offset), count);
    1598                 :            : }
    1599                 :            : 
    1600                 :          0 : static void csi_X(struct vc_data *vc, int vpar) /* erase the following vpar positions */
    1601                 :            : {                                         /* not vt100? */
    1602                 :            :         int count;
    1603                 :            : 
    1604                 :          0 :         if (!vpar)
    1605                 :          0 :                 vpar++;
    1606                 :          0 :         count = (vpar > vc->vc_cols - vc->vc_x) ? (vc->vc_cols - vc->vc_x) : vpar;
    1607                 :            : 
    1608                 :          0 :         vc_uniscr_clear_line(vc, vc->vc_x, count);
    1609                 :          0 :         scr_memsetw((unsigned short *)vc->vc_pos, vc->vc_video_erase_char, 2 * count);
    1610                 :          0 :         if (con_should_update(vc))
    1611                 :          0 :                 vc->vc_sw->con_clear(vc, vc->vc_y, vc->vc_x, 1, count);
    1612                 :          0 :         vc->vc_need_wrap = 0;
    1613                 :          0 : }
    1614                 :            : 
    1615                 :            : static void default_attr(struct vc_data *vc)
    1616                 :            : {
    1617                 :          3 :         vc->vc_intensity = 1;
    1618                 :          3 :         vc->vc_italic = 0;
    1619                 :          3 :         vc->vc_underline = 0;
    1620                 :          3 :         vc->vc_reverse = 0;
    1621                 :          3 :         vc->vc_blink = 0;
    1622                 :          3 :         vc->vc_color = vc->vc_def_color;
    1623                 :            : }
    1624                 :            : 
    1625                 :            : struct rgb { u8 r; u8 g; u8 b; };
    1626                 :            : 
    1627                 :          0 : static void rgb_from_256(int i, struct rgb *c)
    1628                 :            : {
    1629                 :          0 :         if (i < 8) {            /* Standard colours. */
    1630                 :          0 :                 c->r = i&1 ? 0xaa : 0x00;
    1631                 :          0 :                 c->g = i&2 ? 0xaa : 0x00;
    1632                 :          0 :                 c->b = i&4 ? 0xaa : 0x00;
    1633                 :          0 :         } else if (i < 16) {
    1634                 :          0 :                 c->r = i&1 ? 0xff : 0x55;
    1635                 :          0 :                 c->g = i&2 ? 0xff : 0x55;
    1636                 :          0 :                 c->b = i&4 ? 0xff : 0x55;
    1637                 :          0 :         } else if (i < 232) {   /* 6x6x6 colour cube. */
    1638                 :          0 :                 c->r = (i - 16) / 36 * 85 / 2;
    1639                 :          0 :                 c->g = (i - 16) / 6 % 6 * 85 / 2;
    1640                 :          0 :                 c->b = (i - 16) % 6 * 85 / 2;
    1641                 :            :         } else                  /* Grayscale ramp. */
    1642                 :          0 :                 c->r = c->g = c->b = i * 10 - 2312;
    1643                 :          0 : }
    1644                 :            : 
    1645                 :          0 : static void rgb_foreground(struct vc_data *vc, const struct rgb *c)
    1646                 :            : {
    1647                 :          0 :         u8 hue = 0, max = max3(c->r, c->g, c->b);
    1648                 :            : 
    1649                 :          0 :         if (c->r > max / 2)
    1650                 :            :                 hue |= 4;
    1651                 :          0 :         if (c->g > max / 2)
    1652                 :          0 :                 hue |= 2;
    1653                 :          0 :         if (c->b > max / 2)
    1654                 :          0 :                 hue |= 1;
    1655                 :            : 
    1656                 :          0 :         if (hue == 7 && max <= 0x55) {
    1657                 :            :                 hue = 0;
    1658                 :          0 :                 vc->vc_intensity = 2;
    1659                 :          0 :         } else if (max > 0xaa)
    1660                 :          0 :                 vc->vc_intensity = 2;
    1661                 :            :         else
    1662                 :          0 :                 vc->vc_intensity = 1;
    1663                 :            : 
    1664                 :          0 :         vc->vc_color = (vc->vc_color & 0xf0) | hue;
    1665                 :          0 : }
    1666                 :            : 
    1667                 :          0 : static void rgb_background(struct vc_data *vc, const struct rgb *c)
    1668                 :            : {
    1669                 :            :         /* For backgrounds, err on the dark side. */
    1670                 :          0 :         vc->vc_color = (vc->vc_color & 0x0f)
    1671                 :          0 :                 | (c->r&0x80) >> 1 | (c->g&0x80) >> 2 | (c->b&0x80) >> 3;
    1672                 :          0 : }
    1673                 :            : 
    1674                 :            : /*
    1675                 :            :  * ITU T.416 Higher colour modes. They break the usual properties of SGR codes
    1676                 :            :  * and thus need to be detected and ignored by hand. That standard also
    1677                 :            :  * wants : rather than ; as separators but sequences containing : are currently
    1678                 :            :  * completely ignored by the parser.
    1679                 :            :  *
    1680                 :            :  * Subcommands 3 (CMY) and 4 (CMYK) are so insane there's no point in
    1681                 :            :  * supporting them.
    1682                 :            :  */
    1683                 :          0 : static int vc_t416_color(struct vc_data *vc, int i,
    1684                 :            :                 void(*set_color)(struct vc_data *vc, const struct rgb *c))
    1685                 :            : {
    1686                 :            :         struct rgb c;
    1687                 :            : 
    1688                 :          0 :         i++;
    1689                 :          0 :         if (i > vc->vc_npar)
    1690                 :            :                 return i;
    1691                 :            : 
    1692                 :          0 :         if (vc->vc_par[i] == 5 && i + 1 <= vc->vc_npar) {
    1693                 :            :                 /* 256 colours */
    1694                 :            :                 i++;
    1695                 :          0 :                 rgb_from_256(vc->vc_par[i], &c);
    1696                 :          0 :         } else if (vc->vc_par[i] == 2 && i + 3 <= vc->vc_npar) {
    1697                 :            :                 /* 24 bit */
    1698                 :          0 :                 c.r = vc->vc_par[i + 1];
    1699                 :          0 :                 c.g = vc->vc_par[i + 2];
    1700                 :          0 :                 c.b = vc->vc_par[i + 3];
    1701                 :          0 :                 i += 3;
    1702                 :            :         } else
    1703                 :            :                 return i;
    1704                 :            : 
    1705                 :          0 :         set_color(vc, &c);
    1706                 :            : 
    1707                 :          0 :         return i;
    1708                 :            : }
    1709                 :            : 
    1710                 :            : /* console_lock is held */
    1711                 :          3 : static void csi_m(struct vc_data *vc)
    1712                 :            : {
    1713                 :            :         int i;
    1714                 :            : 
    1715                 :          3 :         for (i = 0; i <= vc->vc_npar; i++)
    1716                 :          3 :                 switch (vc->vc_par[i]) {
    1717                 :            :                 case 0: /* all attributes off */
    1718                 :            :                         default_attr(vc);
    1719                 :            :                         break;
    1720                 :            :                 case 1:
    1721                 :          3 :                         vc->vc_intensity = 2;
    1722                 :          3 :                         break;
    1723                 :            :                 case 2:
    1724                 :          0 :                         vc->vc_intensity = 0;
    1725                 :          0 :                         break;
    1726                 :            :                 case 3:
    1727                 :          0 :                         vc->vc_italic = 1;
    1728                 :          0 :                         break;
    1729                 :            :                 case 21:
    1730                 :            :                         /*
    1731                 :            :                          * No console drivers support double underline, so
    1732                 :            :                          * convert it to a single underline.
    1733                 :            :                          */
    1734                 :            :                 case 4:
    1735                 :          0 :                         vc->vc_underline = 1;
    1736                 :          0 :                         break;
    1737                 :            :                 case 5:
    1738                 :          0 :                         vc->vc_blink = 1;
    1739                 :          0 :                         break;
    1740                 :            :                 case 7:
    1741                 :          0 :                         vc->vc_reverse = 1;
    1742                 :          0 :                         break;
    1743                 :            :                 case 10: /* ANSI X3.64-1979 (SCO-ish?)
    1744                 :            :                           * Select primary font, don't display control chars if
    1745                 :            :                           * defined, don't set bit 8 on output.
    1746                 :            :                           */
    1747                 :          0 :                         vc->vc_translate = set_translate(vc->vc_charset == 0
    1748                 :          0 :                                         ? vc->vc_G0_charset
    1749                 :          0 :                                         : vc->vc_G1_charset, vc);
    1750                 :          0 :                         vc->vc_disp_ctrl = 0;
    1751                 :          0 :                         vc->vc_toggle_meta = 0;
    1752                 :          0 :                         break;
    1753                 :            :                 case 11: /* ANSI X3.64-1979 (SCO-ish?)
    1754                 :            :                           * Select first alternate font, lets chars < 32 be
    1755                 :            :                           * displayed as ROM chars.
    1756                 :            :                           */
    1757                 :          0 :                         vc->vc_translate = set_translate(IBMPC_MAP, vc);
    1758                 :          0 :                         vc->vc_disp_ctrl = 1;
    1759                 :          0 :                         vc->vc_toggle_meta = 0;
    1760                 :          0 :                         break;
    1761                 :            :                 case 12: /* ANSI X3.64-1979 (SCO-ish?)
    1762                 :            :                           * Select second alternate font, toggle high bit
    1763                 :            :                           * before displaying as ROM char.
    1764                 :            :                           */
    1765                 :          0 :                         vc->vc_translate = set_translate(IBMPC_MAP, vc);
    1766                 :          0 :                         vc->vc_disp_ctrl = 1;
    1767                 :          0 :                         vc->vc_toggle_meta = 1;
    1768                 :          0 :                         break;
    1769                 :            :                 case 22:
    1770                 :          0 :                         vc->vc_intensity = 1;
    1771                 :          0 :                         break;
    1772                 :            :                 case 23:
    1773                 :          0 :                         vc->vc_italic = 0;
    1774                 :          0 :                         break;
    1775                 :            :                 case 24:
    1776                 :          0 :                         vc->vc_underline = 0;
    1777                 :          0 :                         break;
    1778                 :            :                 case 25:
    1779                 :          0 :                         vc->vc_blink = 0;
    1780                 :          0 :                         break;
    1781                 :            :                 case 27:
    1782                 :          0 :                         vc->vc_reverse = 0;
    1783                 :          0 :                         break;
    1784                 :            :                 case 38:
    1785                 :          0 :                         i = vc_t416_color(vc, i, rgb_foreground);
    1786                 :          0 :                         break;
    1787                 :            :                 case 48:
    1788                 :          0 :                         i = vc_t416_color(vc, i, rgb_background);
    1789                 :          0 :                         break;
    1790                 :            :                 case 39:
    1791                 :          0 :                         vc->vc_color = (vc->vc_def_color & 0x0f) |
    1792                 :          0 :                                 (vc->vc_color & 0xf0);
    1793                 :          0 :                         break;
    1794                 :            :                 case 49:
    1795                 :          0 :                         vc->vc_color = (vc->vc_def_color & 0xf0) |
    1796                 :          0 :                                 (vc->vc_color & 0x0f);
    1797                 :          0 :                         break;
    1798                 :            :                 default:
    1799                 :          3 :                         if (vc->vc_par[i] >= 90 && vc->vc_par[i] <= 107) {
    1800                 :          0 :                                 if (vc->vc_par[i] < 100)
    1801                 :          0 :                                         vc->vc_intensity = 2;
    1802                 :          0 :                                 vc->vc_par[i] -= 60;
    1803                 :            :                         }
    1804                 :          3 :                         if (vc->vc_par[i] >= 30 && vc->vc_par[i] <= 37)
    1805                 :          3 :                                 vc->vc_color = color_table[vc->vc_par[i] - 30]
    1806                 :          3 :                                         | (vc->vc_color & 0xf0);
    1807                 :          0 :                         else if (vc->vc_par[i] >= 40 && vc->vc_par[i] <= 47)
    1808                 :          0 :                                 vc->vc_color = (color_table[vc->vc_par[i] - 40] << 4)
    1809                 :          0 :                                         | (vc->vc_color & 0x0f);
    1810                 :            :                         break;
    1811                 :            :                 }
    1812                 :          3 :         update_attr(vc);
    1813                 :          3 : }
    1814                 :            : 
    1815                 :          0 : static void respond_string(const char *p, struct tty_port *port)
    1816                 :            : {
    1817                 :          0 :         while (*p) {
    1818                 :          0 :                 tty_insert_flip_char(port, *p, 0);
    1819                 :          0 :                 p++;
    1820                 :            :         }
    1821                 :          0 :         tty_schedule_flip(port);
    1822                 :          0 : }
    1823                 :            : 
    1824                 :          0 : static void cursor_report(struct vc_data *vc, struct tty_struct *tty)
    1825                 :            : {
    1826                 :            :         char buf[40];
    1827                 :            : 
    1828                 :          0 :         sprintf(buf, "\033[%d;%dR", vc->vc_y + (vc->vc_decom ? vc->vc_top + 1 : 1), vc->vc_x + 1);
    1829                 :          0 :         respond_string(buf, tty->port);
    1830                 :          0 : }
    1831                 :            : 
    1832                 :            : static inline void status_report(struct tty_struct *tty)
    1833                 :            : {
    1834                 :          0 :         respond_string("\033[0n", tty->port);      /* Terminal ok */
    1835                 :            : }
    1836                 :            : 
    1837                 :            : static inline void respond_ID(struct tty_struct *tty)
    1838                 :            : {
    1839                 :          0 :         respond_string(VT102ID, tty->port);
    1840                 :            : }
    1841                 :            : 
    1842                 :          0 : void mouse_report(struct tty_struct *tty, int butt, int mrx, int mry)
    1843                 :            : {
    1844                 :            :         char buf[8];
    1845                 :            : 
    1846                 :          0 :         sprintf(buf, "\033[M%c%c%c", (char)(' ' + butt), (char)('!' + mrx),
    1847                 :          0 :                 (char)('!' + mry));
    1848                 :          0 :         respond_string(buf, tty->port);
    1849                 :          0 : }
    1850                 :            : 
    1851                 :            : /* invoked via ioctl(TIOCLINUX) and through set_selection_user */
    1852                 :          0 : int mouse_reporting(void)
    1853                 :            : {
    1854                 :          0 :         return vc_cons[fg_console].d->vc_report_mouse;
    1855                 :            : }
    1856                 :            : 
    1857                 :            : /* console_lock is held */
    1858                 :          0 : static void set_mode(struct vc_data *vc, int on_off)
    1859                 :            : {
    1860                 :            :         int i;
    1861                 :            : 
    1862                 :          0 :         for (i = 0; i <= vc->vc_npar; i++)
    1863                 :          0 :                 if (vc->vc_priv == EPdec) {
    1864                 :          0 :                         switch(vc->vc_par[i]) {      /* DEC private modes set/reset */
    1865                 :            :                         case 1:                 /* Cursor keys send ^[Ox/^[[x */
    1866                 :          0 :                                 if (on_off)
    1867                 :          0 :                                         set_kbd(vc, decckm);
    1868                 :            :                                 else
    1869                 :          0 :                                         clr_kbd(vc, decckm);
    1870                 :            :                                 break;
    1871                 :            :                         case 3: /* 80/132 mode switch unimplemented */
    1872                 :            : #if 0
    1873                 :            :                                 vc_resize(deccolm ? 132 : 80, vc->vc_rows);
    1874                 :            :                                 /* this alone does not suffice; some user mode
    1875                 :            :                                    utility has to change the hardware regs */
    1876                 :            : #endif
    1877                 :            :                                 break;
    1878                 :            :                         case 5:                 /* Inverted screen on/off */
    1879                 :          0 :                                 if (vc->vc_decscnm != on_off) {
    1880                 :          0 :                                         vc->vc_decscnm = on_off;
    1881                 :          0 :                                         invert_screen(vc, 0, vc->vc_screenbuf_size, 0);
    1882                 :          0 :                                         update_attr(vc);
    1883                 :            :                                 }
    1884                 :            :                                 break;
    1885                 :            :                         case 6:                 /* Origin relative/absolute */
    1886                 :          0 :                                 vc->vc_decom = on_off;
    1887                 :            :                                 gotoxay(vc, 0, 0);
    1888                 :            :                                 break;
    1889                 :            :                         case 7:                 /* Autowrap on/off */
    1890                 :          0 :                                 vc->vc_decawm = on_off;
    1891                 :          0 :                                 break;
    1892                 :            :                         case 8:                 /* Autorepeat on/off */
    1893                 :          0 :                                 if (on_off)
    1894                 :          0 :                                         set_kbd(vc, decarm);
    1895                 :            :                                 else
    1896                 :          0 :                                         clr_kbd(vc, decarm);
    1897                 :            :                                 break;
    1898                 :            :                         case 9:
    1899                 :          0 :                                 vc->vc_report_mouse = on_off ? 1 : 0;
    1900                 :          0 :                                 break;
    1901                 :            :                         case 25:                /* Cursor on/off */
    1902                 :          0 :                                 vc->vc_deccm = on_off;
    1903                 :          0 :                                 break;
    1904                 :            :                         case 1000:
    1905                 :          0 :                                 vc->vc_report_mouse = on_off ? 2 : 0;
    1906                 :          0 :                                 break;
    1907                 :            :                         }
    1908                 :            :                 } else {
    1909                 :          0 :                         switch(vc->vc_par[i]) {      /* ANSI modes set/reset */
    1910                 :            :                         case 3:                 /* Monitor (display ctrls) */
    1911                 :          0 :                                 vc->vc_disp_ctrl = on_off;
    1912                 :          0 :                                 break;
    1913                 :            :                         case 4:                 /* Insert Mode on/off */
    1914                 :          0 :                                 vc->vc_decim = on_off;
    1915                 :          0 :                                 break;
    1916                 :            :                         case 20:                /* Lf, Enter == CrLf/Lf */
    1917                 :          0 :                                 if (on_off)
    1918                 :          0 :                                         set_kbd(vc, lnm);
    1919                 :            :                                 else
    1920                 :          0 :                                         clr_kbd(vc, lnm);
    1921                 :            :                                 break;
    1922                 :            :                         }
    1923                 :            :                 }
    1924                 :          0 : }
    1925                 :            : 
    1926                 :            : /* console_lock is held */
    1927                 :          0 : static void setterm_command(struct vc_data *vc)
    1928                 :            : {
    1929                 :          0 :         switch(vc->vc_par[0]) {
    1930                 :            :                 case 1: /* set color for underline mode */
    1931                 :          0 :                         if (vc->vc_can_do_color &&
    1932                 :          0 :                                         vc->vc_par[1] < 16) {
    1933                 :          0 :                                 vc->vc_ulcolor = color_table[vc->vc_par[1]];
    1934                 :          0 :                                 if (vc->vc_underline)
    1935                 :          0 :                                         update_attr(vc);
    1936                 :            :                         }
    1937                 :            :                         break;
    1938                 :            :                 case 2: /* set color for half intensity mode */
    1939                 :          0 :                         if (vc->vc_can_do_color &&
    1940                 :          0 :                                         vc->vc_par[1] < 16) {
    1941                 :          0 :                                 vc->vc_halfcolor = color_table[vc->vc_par[1]];
    1942                 :          0 :                                 if (vc->vc_intensity == 0)
    1943                 :          0 :                                         update_attr(vc);
    1944                 :            :                         }
    1945                 :            :                         break;
    1946                 :            :                 case 8: /* store colors as defaults */
    1947                 :          0 :                         vc->vc_def_color = vc->vc_attr;
    1948                 :          0 :                         if (vc->vc_hi_font_mask == 0x100)
    1949                 :          0 :                                 vc->vc_def_color >>= 1;
    1950                 :            :                         default_attr(vc);
    1951                 :          0 :                         update_attr(vc);
    1952                 :          0 :                         break;
    1953                 :            :                 case 9: /* set blanking interval */
    1954                 :          0 :                         blankinterval = ((vc->vc_par[1] < 60) ? vc->vc_par[1] : 60) * 60;
    1955                 :          0 :                         poke_blanked_console();
    1956                 :          0 :                         break;
    1957                 :            :                 case 10: /* set bell frequency in Hz */
    1958                 :          0 :                         if (vc->vc_npar >= 1)
    1959                 :          0 :                                 vc->vc_bell_pitch = vc->vc_par[1];
    1960                 :            :                         else
    1961                 :          0 :                                 vc->vc_bell_pitch = DEFAULT_BELL_PITCH;
    1962                 :            :                         break;
    1963                 :            :                 case 11: /* set bell duration in msec */
    1964                 :          0 :                         if (vc->vc_npar >= 1)
    1965                 :          0 :                                 vc->vc_bell_duration = (vc->vc_par[1] < 2000) ?
    1966                 :            :                                         msecs_to_jiffies(vc->vc_par[1]) : 0;
    1967                 :            :                         else
    1968                 :          0 :                                 vc->vc_bell_duration = DEFAULT_BELL_DURATION;
    1969                 :            :                         break;
    1970                 :            :                 case 12: /* bring specified console to the front */
    1971                 :          0 :                         if (vc->vc_par[1] >= 1 && vc_cons_allocated(vc->vc_par[1] - 1))
    1972                 :          0 :                                 set_console(vc->vc_par[1] - 1);
    1973                 :            :                         break;
    1974                 :            :                 case 13: /* unblank the screen */
    1975                 :          0 :                         poke_blanked_console();
    1976                 :          0 :                         break;
    1977                 :            :                 case 14: /* set vesa powerdown interval */
    1978                 :          0 :                         vesa_off_interval = ((vc->vc_par[1] < 60) ? vc->vc_par[1] : 60) * 60 * HZ;
    1979                 :          0 :                         break;
    1980                 :            :                 case 15: /* activate the previous console */
    1981                 :          0 :                         set_console(last_console);
    1982                 :          0 :                         break;
    1983                 :            :                 case 16: /* set cursor blink duration in msec */
    1984                 :          0 :                         if (vc->vc_npar >= 1 && vc->vc_par[1] >= 50 &&
    1985                 :            :                                         vc->vc_par[1] <= USHRT_MAX)
    1986                 :          0 :                                 vc->vc_cur_blink_ms = vc->vc_par[1];
    1987                 :            :                         else
    1988                 :          0 :                                 vc->vc_cur_blink_ms = DEFAULT_CURSOR_BLINK_MS;
    1989                 :            :                         break;
    1990                 :            :         }
    1991                 :          0 : }
    1992                 :            : 
    1993                 :            : /* console_lock is held */
    1994                 :          0 : static void csi_at(struct vc_data *vc, unsigned int nr)
    1995                 :            : {
    1996                 :          0 :         if (nr > vc->vc_cols - vc->vc_x)
    1997                 :            :                 nr = vc->vc_cols - vc->vc_x;
    1998                 :          0 :         else if (!nr)
    1999                 :            :                 nr = 1;
    2000                 :          0 :         insert_char(vc, nr);
    2001                 :          0 : }
    2002                 :            : 
    2003                 :            : /* console_lock is held */
    2004                 :          0 : static void csi_L(struct vc_data *vc, unsigned int nr)
    2005                 :            : {
    2006                 :          0 :         if (nr > vc->vc_rows - vc->vc_y)
    2007                 :            :                 nr = vc->vc_rows - vc->vc_y;
    2008                 :          0 :         else if (!nr)
    2009                 :            :                 nr = 1;
    2010                 :          0 :         con_scroll(vc, vc->vc_y, vc->vc_bottom, SM_DOWN, nr);
    2011                 :          0 :         vc->vc_need_wrap = 0;
    2012                 :          0 : }
    2013                 :            : 
    2014                 :            : /* console_lock is held */
    2015                 :          0 : static void csi_P(struct vc_data *vc, unsigned int nr)
    2016                 :            : {
    2017                 :          0 :         if (nr > vc->vc_cols - vc->vc_x)
    2018                 :            :                 nr = vc->vc_cols - vc->vc_x;
    2019                 :          0 :         else if (!nr)
    2020                 :            :                 nr = 1;
    2021                 :          0 :         delete_char(vc, nr);
    2022                 :          0 : }
    2023                 :            : 
    2024                 :            : /* console_lock is held */
    2025                 :          0 : static void csi_M(struct vc_data *vc, unsigned int nr)
    2026                 :            : {
    2027                 :          0 :         if (nr > vc->vc_rows - vc->vc_y)
    2028                 :            :                 nr = vc->vc_rows - vc->vc_y;
    2029                 :          0 :         else if (!nr)
    2030                 :            :                 nr=1;
    2031                 :          0 :         con_scroll(vc, vc->vc_y, vc->vc_bottom, SM_UP, nr);
    2032                 :          0 :         vc->vc_need_wrap = 0;
    2033                 :          0 : }
    2034                 :            : 
    2035                 :            : /* console_lock is held (except via vc_init->reset_terminal */
    2036                 :            : static void save_cur(struct vc_data *vc)
    2037                 :            : {
    2038                 :          3 :         vc->vc_saved_x               = vc->vc_x;
    2039                 :          3 :         vc->vc_saved_y               = vc->vc_y;
    2040                 :          3 :         vc->vc_s_intensity   = vc->vc_intensity;
    2041                 :          3 :         vc->vc_s_italic         = vc->vc_italic;
    2042                 :          3 :         vc->vc_s_underline   = vc->vc_underline;
    2043                 :          3 :         vc->vc_s_blink               = vc->vc_blink;
    2044                 :          3 :         vc->vc_s_reverse     = vc->vc_reverse;
    2045                 :          3 :         vc->vc_s_charset     = vc->vc_charset;
    2046                 :          3 :         vc->vc_s_color               = vc->vc_color;
    2047                 :          3 :         vc->vc_saved_G0              = vc->vc_G0_charset;
    2048                 :          3 :         vc->vc_saved_G1              = vc->vc_G1_charset;
    2049                 :            : }
    2050                 :            : 
    2051                 :            : /* console_lock is held */
    2052                 :          0 : static void restore_cur(struct vc_data *vc)
    2053                 :            : {
    2054                 :          0 :         gotoxy(vc, vc->vc_saved_x, vc->vc_saved_y);
    2055                 :          0 :         vc->vc_intensity     = vc->vc_s_intensity;
    2056                 :          0 :         vc->vc_italic                = vc->vc_s_italic;
    2057                 :          0 :         vc->vc_underline     = vc->vc_s_underline;
    2058                 :          0 :         vc->vc_blink         = vc->vc_s_blink;
    2059                 :          0 :         vc->vc_reverse               = vc->vc_s_reverse;
    2060                 :          0 :         vc->vc_charset               = vc->vc_s_charset;
    2061                 :          0 :         vc->vc_color         = vc->vc_s_color;
    2062                 :          0 :         vc->vc_G0_charset    = vc->vc_saved_G0;
    2063                 :          0 :         vc->vc_G1_charset    = vc->vc_saved_G1;
    2064                 :          0 :         vc->vc_translate     = set_translate(vc->vc_charset ? vc->vc_G1_charset : vc->vc_G0_charset, vc);
    2065                 :          0 :         update_attr(vc);
    2066                 :          0 :         vc->vc_need_wrap = 0;
    2067                 :          0 : }
    2068                 :            : 
    2069                 :            : enum { ESnormal, ESesc, ESsquare, ESgetpars, ESfunckey,
    2070                 :            :         EShash, ESsetG0, ESsetG1, ESpercent, EScsiignore, ESnonstd,
    2071                 :            :         ESpalette, ESosc };
    2072                 :            : 
    2073                 :            : /* console_lock is held (except via vc_init()) */
    2074                 :          3 : static void reset_terminal(struct vc_data *vc, int do_clear)
    2075                 :            : {
    2076                 :          3 :         vc->vc_top           = 0;
    2077                 :          3 :         vc->vc_bottom                = vc->vc_rows;
    2078                 :          3 :         vc->vc_state         = ESnormal;
    2079                 :          3 :         vc->vc_priv          = EPecma;
    2080                 :          3 :         vc->vc_translate     = set_translate(LAT1_MAP, vc);
    2081                 :          3 :         vc->vc_G0_charset    = LAT1_MAP;
    2082                 :          3 :         vc->vc_G1_charset    = GRAF_MAP;
    2083                 :          3 :         vc->vc_charset               = 0;
    2084                 :          3 :         vc->vc_need_wrap     = 0;
    2085                 :          3 :         vc->vc_report_mouse  = 0;
    2086                 :          3 :         vc->vc_utf              = default_utf8;
    2087                 :          3 :         vc->vc_utf_count     = 0;
    2088                 :            : 
    2089                 :          3 :         vc->vc_disp_ctrl     = 0;
    2090                 :          3 :         vc->vc_toggle_meta   = 0;
    2091                 :            : 
    2092                 :          3 :         vc->vc_decscnm               = 0;
    2093                 :          3 :         vc->vc_decom         = 0;
    2094                 :          3 :         vc->vc_decawm                = 1;
    2095                 :          3 :         vc->vc_deccm         = global_cursor_default;
    2096                 :          3 :         vc->vc_decim         = 0;
    2097                 :            : 
    2098                 :          3 :         vt_reset_keyboard(vc->vc_num);
    2099                 :            : 
    2100                 :          3 :         vc->vc_cursor_type = cur_default;
    2101                 :          3 :         vc->vc_complement_mask = vc->vc_s_complement_mask;
    2102                 :            : 
    2103                 :            :         default_attr(vc);
    2104                 :          3 :         update_attr(vc);
    2105                 :            : 
    2106                 :          3 :         vc->vc_tab_stop[0]   =
    2107                 :          3 :         vc->vc_tab_stop[1]   =
    2108                 :          3 :         vc->vc_tab_stop[2]   =
    2109                 :          3 :         vc->vc_tab_stop[3]   =
    2110                 :          3 :         vc->vc_tab_stop[4]   =
    2111                 :          3 :         vc->vc_tab_stop[5]   =
    2112                 :          3 :         vc->vc_tab_stop[6]   =
    2113                 :          3 :         vc->vc_tab_stop[7]   = 0x01010101;
    2114                 :            : 
    2115                 :          3 :         vc->vc_bell_pitch = DEFAULT_BELL_PITCH;
    2116                 :          3 :         vc->vc_bell_duration = DEFAULT_BELL_DURATION;
    2117                 :          3 :         vc->vc_cur_blink_ms = DEFAULT_CURSOR_BLINK_MS;
    2118                 :            : 
    2119                 :          3 :         gotoxy(vc, 0, 0);
    2120                 :            :         save_cur(vc);
    2121                 :          3 :         if (do_clear)
    2122                 :          3 :             csi_J(vc, 2);
    2123                 :          3 : }
    2124                 :            : 
    2125                 :            : /* console_lock is held */
    2126                 :          3 : static void do_con_trol(struct tty_struct *tty, struct vc_data *vc, int c)
    2127                 :            : {
    2128                 :            :         /*
    2129                 :            :          *  Control characters can be used in the _middle_
    2130                 :            :          *  of an escape sequence.
    2131                 :            :          */
    2132                 :          3 :         if (vc->vc_state == ESosc && c>=8 && c<=13) /* ... except for OSC */
    2133                 :            :                 return;
    2134                 :          3 :         switch (c) {
    2135                 :            :         case 0:
    2136                 :            :                 return;
    2137                 :            :         case 7:
    2138                 :          0 :                 if (vc->vc_state == ESosc)
    2139                 :          0 :                         vc->vc_state = ESnormal;
    2140                 :          0 :                 else if (vc->vc_bell_duration)
    2141                 :          0 :                         kd_mksound(vc->vc_bell_pitch, vc->vc_bell_duration);
    2142                 :            :                 return;
    2143                 :            :         case 8:
    2144                 :          0 :                 bs(vc);
    2145                 :          0 :                 return;
    2146                 :            :         case 9:
    2147                 :          0 :                 vc->vc_pos -= (vc->vc_x << 1);
    2148                 :          0 :                 while (vc->vc_x < vc->vc_cols - 1) {
    2149                 :          0 :                         vc->vc_x++;
    2150                 :          0 :                         if (vc->vc_tab_stop[7 & (vc->vc_x >> 5)] & (1 << (vc->vc_x & 31)))
    2151                 :            :                                 break;
    2152                 :            :                 }
    2153                 :          0 :                 vc->vc_pos += (vc->vc_x << 1);
    2154                 :            :                 notify_write(vc, '\t');
    2155                 :            :                 return;
    2156                 :            :         case 10: case 11: case 12:
    2157                 :          3 :                 lf(vc);
    2158                 :          3 :                 if (!is_kbd(vc, lnm))
    2159                 :            :                         return;
    2160                 :            :                 /* fall through */
    2161                 :            :         case 13:
    2162                 :          3 :                 cr(vc);
    2163                 :          3 :                 return;
    2164                 :            :         case 14:
    2165                 :          0 :                 vc->vc_charset = 1;
    2166                 :          0 :                 vc->vc_translate = set_translate(vc->vc_G1_charset, vc);
    2167                 :          0 :                 vc->vc_disp_ctrl = 1;
    2168                 :          0 :                 return;
    2169                 :            :         case 15:
    2170                 :          0 :                 vc->vc_charset = 0;
    2171                 :          0 :                 vc->vc_translate = set_translate(vc->vc_G0_charset, vc);
    2172                 :          0 :                 vc->vc_disp_ctrl = 0;
    2173                 :          0 :                 return;
    2174                 :            :         case 24: case 26:
    2175                 :          0 :                 vc->vc_state = ESnormal;
    2176                 :          0 :                 return;
    2177                 :            :         case 27:
    2178                 :          3 :                 vc->vc_state = ESesc;
    2179                 :          3 :                 return;
    2180                 :            :         case 127:
    2181                 :            :                 del(vc);
    2182                 :            :                 return;
    2183                 :            :         case 128+27:
    2184                 :          0 :                 vc->vc_state = ESsquare;
    2185                 :          0 :                 return;
    2186                 :            :         }
    2187                 :          3 :         switch(vc->vc_state) {
    2188                 :            :         case ESesc:
    2189                 :          3 :                 vc->vc_state = ESnormal;
    2190                 :          3 :                 switch (c) {
    2191                 :            :                 case '[':
    2192                 :          3 :                         vc->vc_state = ESsquare;
    2193                 :          3 :                         return;
    2194                 :            :                 case ']':
    2195                 :          0 :                         vc->vc_state = ESnonstd;
    2196                 :          0 :                         return;
    2197                 :            :                 case '%':
    2198                 :          3 :                         vc->vc_state = ESpercent;
    2199                 :          3 :                         return;
    2200                 :            :                 case 'E':
    2201                 :          0 :                         cr(vc);
    2202                 :          0 :                         lf(vc);
    2203                 :          0 :                         return;
    2204                 :            :                 case 'M':
    2205                 :          0 :                         ri(vc);
    2206                 :          0 :                         return;
    2207                 :            :                 case 'D':
    2208                 :          0 :                         lf(vc);
    2209                 :          0 :                         return;
    2210                 :            :                 case 'H':
    2211                 :          0 :                         vc->vc_tab_stop[7 & (vc->vc_x >> 5)] |= (1 << (vc->vc_x & 31));
    2212                 :          0 :                         return;
    2213                 :            :                 case 'Z':
    2214                 :            :                         respond_ID(tty);
    2215                 :            :                         return;
    2216                 :            :                 case '7':
    2217                 :            :                         save_cur(vc);
    2218                 :            :                         return;
    2219                 :            :                 case '8':
    2220                 :          0 :                         restore_cur(vc);
    2221                 :          0 :                         return;
    2222                 :            :                 case '(':
    2223                 :          0 :                         vc->vc_state = ESsetG0;
    2224                 :          0 :                         return;
    2225                 :            :                 case ')':
    2226                 :          0 :                         vc->vc_state = ESsetG1;
    2227                 :          0 :                         return;
    2228                 :            :                 case '#':
    2229                 :          0 :                         vc->vc_state = EShash;
    2230                 :          0 :                         return;
    2231                 :            :                 case 'c':
    2232                 :          0 :                         reset_terminal(vc, 1);
    2233                 :          0 :                         return;
    2234                 :            :                 case '>':  /* Numeric keypad */
    2235                 :          0 :                         clr_kbd(vc, kbdapplic);
    2236                 :          0 :                         return;
    2237                 :            :                 case '=':  /* Appl. keypad */
    2238                 :          0 :                         set_kbd(vc, kbdapplic);
    2239                 :          0 :                         return;
    2240                 :            :                 }
    2241                 :            :                 return;
    2242                 :            :         case ESnonstd:
    2243                 :          0 :                 if (c=='P') {   /* palette escape sequence */
    2244                 :          0 :                         for (vc->vc_npar = 0; vc->vc_npar < NPAR; vc->vc_npar++)
    2245                 :          0 :                                 vc->vc_par[vc->vc_npar] = 0;
    2246                 :          0 :                         vc->vc_npar = 0;
    2247                 :          0 :                         vc->vc_state = ESpalette;
    2248                 :          0 :                         return;
    2249                 :          0 :                 } else if (c=='R') {   /* reset palette */
    2250                 :          0 :                         reset_palette(vc);
    2251                 :          0 :                         vc->vc_state = ESnormal;
    2252                 :          0 :                 } else if (c>='0' && c<='9')
    2253                 :          0 :                         vc->vc_state = ESosc;
    2254                 :            :                 else
    2255                 :          0 :                         vc->vc_state = ESnormal;
    2256                 :            :                 return;
    2257                 :            :         case ESpalette:
    2258                 :          0 :                 if (isxdigit(c)) {
    2259                 :          0 :                         vc->vc_par[vc->vc_npar++] = hex_to_bin(c);
    2260                 :          0 :                         if (vc->vc_npar == 7) {
    2261                 :          0 :                                 int i = vc->vc_par[0] * 3, j = 1;
    2262                 :          0 :                                 vc->vc_palette[i] = 16 * vc->vc_par[j++];
    2263                 :          0 :                                 vc->vc_palette[i++] += vc->vc_par[j++];
    2264                 :          0 :                                 vc->vc_palette[i] = 16 * vc->vc_par[j++];
    2265                 :          0 :                                 vc->vc_palette[i++] += vc->vc_par[j++];
    2266                 :          0 :                                 vc->vc_palette[i] = 16 * vc->vc_par[j++];
    2267                 :          0 :                                 vc->vc_palette[i] += vc->vc_par[j];
    2268                 :          0 :                                 set_palette(vc);
    2269                 :          0 :                                 vc->vc_state = ESnormal;
    2270                 :            :                         }
    2271                 :            :                 } else
    2272                 :          0 :                         vc->vc_state = ESnormal;
    2273                 :            :                 return;
    2274                 :            :         case ESsquare:
    2275                 :          3 :                 for (vc->vc_npar = 0; vc->vc_npar < NPAR; vc->vc_npar++)
    2276                 :          3 :                         vc->vc_par[vc->vc_npar] = 0;
    2277                 :          3 :                 vc->vc_npar = 0;
    2278                 :          3 :                 vc->vc_state = ESgetpars;
    2279                 :          3 :                 if (c == '[') { /* Function key */
    2280                 :          0 :                         vc->vc_state=ESfunckey;
    2281                 :          0 :                         return;
    2282                 :            :                 }
    2283                 :          3 :                 switch (c) {
    2284                 :            :                 case '?':
    2285                 :          0 :                         vc->vc_priv = EPdec;
    2286                 :          0 :                         return;
    2287                 :            :                 case '>':
    2288                 :          0 :                         vc->vc_priv = EPgt;
    2289                 :          0 :                         return;
    2290                 :            :                 case '=':
    2291                 :          0 :                         vc->vc_priv = EPeq;
    2292                 :          0 :                         return;
    2293                 :            :                 case '<':
    2294                 :          0 :                         vc->vc_priv = EPlt;
    2295                 :          0 :                         return;
    2296                 :            :                 }
    2297                 :          3 :                 vc->vc_priv = EPecma;
    2298                 :            :                 /* fall through */
    2299                 :            :         case ESgetpars:
    2300                 :          3 :                 if (c == ';' && vc->vc_npar < NPAR - 1) {
    2301                 :          3 :                         vc->vc_npar++;
    2302                 :          3 :                         return;
    2303                 :          3 :                 } else if (c>='0' && c<='9') {
    2304                 :          3 :                         vc->vc_par[vc->vc_npar] *= 10;
    2305                 :          3 :                         vc->vc_par[vc->vc_npar] += c - '0';
    2306                 :          3 :                         return;
    2307                 :            :                 }
    2308                 :          3 :                 if (c >= 0x20 && c <= 0x3f) { /* 0x2x, 0x3a and 0x3c - 0x3f */
    2309                 :          0 :                         vc->vc_state = EScsiignore;
    2310                 :          0 :                         return;
    2311                 :            :                 }
    2312                 :          3 :                 vc->vc_state = ESnormal;
    2313                 :          3 :                 switch(c) {
    2314                 :            :                 case 'h':
    2315                 :          0 :                         if (vc->vc_priv <= EPdec)
    2316                 :          0 :                                 set_mode(vc, 1);
    2317                 :            :                         return;
    2318                 :            :                 case 'l':
    2319                 :          0 :                         if (vc->vc_priv <= EPdec)
    2320                 :          0 :                                 set_mode(vc, 0);
    2321                 :            :                         return;
    2322                 :            :                 case 'c':
    2323                 :          0 :                         if (vc->vc_priv == EPdec) {
    2324                 :          0 :                                 if (vc->vc_par[0])
    2325                 :          0 :                                         vc->vc_cursor_type = vc->vc_par[0] | (vc->vc_par[1] << 8) | (vc->vc_par[2] << 16);
    2326                 :            :                                 else
    2327                 :          0 :                                         vc->vc_cursor_type = cur_default;
    2328                 :            :                                 return;
    2329                 :            :                         }
    2330                 :            :                         break;
    2331                 :            :                 case 'm':
    2332                 :          3 :                         if (vc->vc_priv == EPdec) {
    2333                 :          0 :                                 clear_selection();
    2334                 :          0 :                                 if (vc->vc_par[0])
    2335                 :          0 :                                         vc->vc_complement_mask = vc->vc_par[0] << 8 | vc->vc_par[1];
    2336                 :            :                                 else
    2337                 :          0 :                                         vc->vc_complement_mask = vc->vc_s_complement_mask;
    2338                 :            :                                 return;
    2339                 :            :                         }
    2340                 :            :                         break;
    2341                 :            :                 case 'n':
    2342                 :          0 :                         if (vc->vc_priv == EPecma) {
    2343                 :          0 :                                 if (vc->vc_par[0] == 5)
    2344                 :            :                                         status_report(tty);
    2345                 :          0 :                                 else if (vc->vc_par[0] == 6)
    2346                 :          0 :                                         cursor_report(vc, tty);
    2347                 :            :                         }
    2348                 :            :                         return;
    2349                 :            :                 }
    2350                 :          3 :                 if (vc->vc_priv != EPecma) {
    2351                 :          0 :                         vc->vc_priv = EPecma;
    2352                 :          0 :                         return;
    2353                 :            :                 }
    2354                 :          3 :                 switch(c) {
    2355                 :            :                 case 'G': case '`':
    2356                 :          0 :                         if (vc->vc_par[0])
    2357                 :          0 :                                 vc->vc_par[0]--;
    2358                 :          0 :                         gotoxy(vc, vc->vc_par[0], vc->vc_y);
    2359                 :          0 :                         return;
    2360                 :            :                 case 'A':
    2361                 :          0 :                         if (!vc->vc_par[0])
    2362                 :          0 :                                 vc->vc_par[0]++;
    2363                 :          0 :                         gotoxy(vc, vc->vc_x, vc->vc_y - vc->vc_par[0]);
    2364                 :          0 :                         return;
    2365                 :            :                 case 'B': case 'e':
    2366                 :          0 :                         if (!vc->vc_par[0])
    2367                 :          0 :                                 vc->vc_par[0]++;
    2368                 :          0 :                         gotoxy(vc, vc->vc_x, vc->vc_y + vc->vc_par[0]);
    2369                 :          0 :                         return;
    2370                 :            :                 case 'C': case 'a':
    2371                 :          0 :                         if (!vc->vc_par[0])
    2372                 :          0 :                                 vc->vc_par[0]++;
    2373                 :          0 :                         gotoxy(vc, vc->vc_x + vc->vc_par[0], vc->vc_y);
    2374                 :          0 :                         return;
    2375                 :            :                 case 'D':
    2376                 :          0 :                         if (!vc->vc_par[0])
    2377                 :          0 :                                 vc->vc_par[0]++;
    2378                 :          0 :                         gotoxy(vc, vc->vc_x - vc->vc_par[0], vc->vc_y);
    2379                 :          0 :                         return;
    2380                 :            :                 case 'E':
    2381                 :          0 :                         if (!vc->vc_par[0])
    2382                 :          0 :                                 vc->vc_par[0]++;
    2383                 :          0 :                         gotoxy(vc, 0, vc->vc_y + vc->vc_par[0]);
    2384                 :          0 :                         return;
    2385                 :            :                 case 'F':
    2386                 :          0 :                         if (!vc->vc_par[0])
    2387                 :          0 :                                 vc->vc_par[0]++;
    2388                 :          0 :                         gotoxy(vc, 0, vc->vc_y - vc->vc_par[0]);
    2389                 :          0 :                         return;
    2390                 :            :                 case 'd':
    2391                 :          0 :                         if (vc->vc_par[0])
    2392                 :          0 :                                 vc->vc_par[0]--;
    2393                 :          0 :                         gotoxay(vc, vc->vc_x ,vc->vc_par[0]);
    2394                 :            :                         return;
    2395                 :            :                 case 'H': case 'f':
    2396                 :          0 :                         if (vc->vc_par[0])
    2397                 :          0 :                                 vc->vc_par[0]--;
    2398                 :          0 :                         if (vc->vc_par[1])
    2399                 :          0 :                                 vc->vc_par[1]--;
    2400                 :          0 :                         gotoxay(vc, vc->vc_par[1], vc->vc_par[0]);
    2401                 :            :                         return;
    2402                 :            :                 case 'J':
    2403                 :          0 :                         csi_J(vc, vc->vc_par[0]);
    2404                 :          0 :                         return;
    2405                 :            :                 case 'K':
    2406                 :          0 :                         csi_K(vc, vc->vc_par[0]);
    2407                 :          0 :                         return;
    2408                 :            :                 case 'L':
    2409                 :          0 :                         csi_L(vc, vc->vc_par[0]);
    2410                 :          0 :                         return;
    2411                 :            :                 case 'M':
    2412                 :          0 :                         csi_M(vc, vc->vc_par[0]);
    2413                 :          0 :                         return;
    2414                 :            :                 case 'P':
    2415                 :          0 :                         csi_P(vc, vc->vc_par[0]);
    2416                 :          0 :                         return;
    2417                 :            :                 case 'c':
    2418                 :          0 :                         if (!vc->vc_par[0])
    2419                 :            :                                 respond_ID(tty);
    2420                 :            :                         return;
    2421                 :            :                 case 'g':
    2422                 :          0 :                         if (!vc->vc_par[0])
    2423                 :          0 :                                 vc->vc_tab_stop[7 & (vc->vc_x >> 5)] &= ~(1 << (vc->vc_x & 31));
    2424                 :          0 :                         else if (vc->vc_par[0] == 3) {
    2425                 :          0 :                                 vc->vc_tab_stop[0] =
    2426                 :          0 :                                         vc->vc_tab_stop[1] =
    2427                 :          0 :                                         vc->vc_tab_stop[2] =
    2428                 :          0 :                                         vc->vc_tab_stop[3] =
    2429                 :          0 :                                         vc->vc_tab_stop[4] =
    2430                 :          0 :                                         vc->vc_tab_stop[5] =
    2431                 :          0 :                                         vc->vc_tab_stop[6] =
    2432                 :          0 :                                         vc->vc_tab_stop[7] = 0;
    2433                 :            :                         }
    2434                 :            :                         return;
    2435                 :            :                 case 'm':
    2436                 :          3 :                         csi_m(vc);
    2437                 :          3 :                         return;
    2438                 :            :                 case 'q': /* DECLL - but only 3 leds */
    2439                 :            :                         /* map 0,1,2,3 to 0,1,2,4 */
    2440                 :          0 :                         if (vc->vc_par[0] < 4)
    2441                 :          0 :                                 vt_set_led_state(vc->vc_num,
    2442                 :            :                                             (vc->vc_par[0] < 3) ? vc->vc_par[0] : 4);
    2443                 :            :                         return;
    2444                 :            :                 case 'r':
    2445                 :          0 :                         if (!vc->vc_par[0])
    2446                 :          0 :                                 vc->vc_par[0]++;
    2447                 :          0 :                         if (!vc->vc_par[1])
    2448                 :          0 :                                 vc->vc_par[1] = vc->vc_rows;
    2449                 :            :                         /* Minimum allowed region is 2 lines */
    2450                 :          0 :                         if (vc->vc_par[0] < vc->vc_par[1] &&
    2451                 :          0 :                             vc->vc_par[1] <= vc->vc_rows) {
    2452                 :          0 :                                 vc->vc_top = vc->vc_par[0] - 1;
    2453                 :          0 :                                 vc->vc_bottom = vc->vc_par[1];
    2454                 :            :                                 gotoxay(vc, 0, 0);
    2455                 :            :                         }
    2456                 :            :                         return;
    2457                 :            :                 case 's':
    2458                 :            :                         save_cur(vc);
    2459                 :            :                         return;
    2460                 :            :                 case 'u':
    2461                 :          0 :                         restore_cur(vc);
    2462                 :          0 :                         return;
    2463                 :            :                 case 'X':
    2464                 :          0 :                         csi_X(vc, vc->vc_par[0]);
    2465                 :          0 :                         return;
    2466                 :            :                 case '@':
    2467                 :          0 :                         csi_at(vc, vc->vc_par[0]);
    2468                 :          0 :                         return;
    2469                 :            :                 case ']': /* setterm functions */
    2470                 :          0 :                         setterm_command(vc);
    2471                 :          0 :                         return;
    2472                 :            :                 }
    2473                 :            :                 return;
    2474                 :            :         case EScsiignore:
    2475                 :          0 :                 if (c >= 20 && c <= 0x3f)
    2476                 :            :                         return;
    2477                 :          0 :                 vc->vc_state = ESnormal;
    2478                 :          0 :                 return;
    2479                 :            :         case ESpercent:
    2480                 :          3 :                 vc->vc_state = ESnormal;
    2481                 :          3 :                 switch (c) {
    2482                 :            :                 case '@':  /* defined in ISO 2022 */
    2483                 :          0 :                         vc->vc_utf = 0;
    2484                 :          0 :                         return;
    2485                 :            :                 case 'G':  /* prelim official escape code */
    2486                 :            :                 case '8':  /* retained for compatibility */
    2487                 :          3 :                         vc->vc_utf = 1;
    2488                 :          3 :                         return;
    2489                 :            :                 }
    2490                 :            :                 return;
    2491                 :            :         case ESfunckey:
    2492                 :          0 :                 vc->vc_state = ESnormal;
    2493                 :          0 :                 return;
    2494                 :            :         case EShash:
    2495                 :          0 :                 vc->vc_state = ESnormal;
    2496                 :          0 :                 if (c == '8') {
    2497                 :            :                         /* DEC screen alignment test. kludge :-) */
    2498                 :          0 :                         vc->vc_video_erase_char =
    2499                 :          0 :                                 (vc->vc_video_erase_char & 0xff00) | 'E';
    2500                 :          0 :                         csi_J(vc, 2);
    2501                 :          0 :                         vc->vc_video_erase_char =
    2502                 :          0 :                                 (vc->vc_video_erase_char & 0xff00) | ' ';
    2503                 :          0 :                         do_update_region(vc, vc->vc_origin, vc->vc_screenbuf_size / 2);
    2504                 :            :                 }
    2505                 :            :                 return;
    2506                 :            :         case ESsetG0:
    2507                 :          0 :                 if (c == '0')
    2508                 :          0 :                         vc->vc_G0_charset = GRAF_MAP;
    2509                 :          0 :                 else if (c == 'B')
    2510                 :          0 :                         vc->vc_G0_charset = LAT1_MAP;
    2511                 :          0 :                 else if (c == 'U')
    2512                 :          0 :                         vc->vc_G0_charset = IBMPC_MAP;
    2513                 :          0 :                 else if (c == 'K')
    2514                 :          0 :                         vc->vc_G0_charset = USER_MAP;
    2515                 :          0 :                 if (vc->vc_charset == 0)
    2516                 :          0 :                         vc->vc_translate = set_translate(vc->vc_G0_charset, vc);
    2517                 :          0 :                 vc->vc_state = ESnormal;
    2518                 :          0 :                 return;
    2519                 :            :         case ESsetG1:
    2520                 :          0 :                 if (c == '0')
    2521                 :          0 :                         vc->vc_G1_charset = GRAF_MAP;
    2522                 :          0 :                 else if (c == 'B')
    2523                 :          0 :                         vc->vc_G1_charset = LAT1_MAP;
    2524                 :          0 :                 else if (c == 'U')
    2525                 :          0 :                         vc->vc_G1_charset = IBMPC_MAP;
    2526                 :          0 :                 else if (c == 'K')
    2527                 :          0 :                         vc->vc_G1_charset = USER_MAP;
    2528                 :          0 :                 if (vc->vc_charset == 1)
    2529                 :          0 :                         vc->vc_translate = set_translate(vc->vc_G1_charset, vc);
    2530                 :          0 :                 vc->vc_state = ESnormal;
    2531                 :          0 :                 return;
    2532                 :            :         case ESosc:
    2533                 :            :                 return;
    2534                 :            :         default:
    2535                 :          0 :                 vc->vc_state = ESnormal;
    2536                 :            :         }
    2537                 :            : }
    2538                 :            : 
    2539                 :            : /* is_double_width() is based on the wcwidth() implementation by
    2540                 :            :  * Markus Kuhn -- 2007-05-26 (Unicode 5.0)
    2541                 :            :  * Latest version: http://www.cl.cam.ac.uk/~mgk25/ucs/wcwidth.c
    2542                 :            :  */
    2543                 :            : struct interval {
    2544                 :            :         uint32_t first;
    2545                 :            :         uint32_t last;
    2546                 :            : };
    2547                 :            : 
    2548                 :          0 : static int ucs_cmp(const void *key, const void *elt)
    2549                 :            : {
    2550                 :          0 :         uint32_t ucs = *(uint32_t *)key;
    2551                 :          0 :         struct interval e = *(struct interval *) elt;
    2552                 :            : 
    2553                 :          0 :         if (ucs > e.last)
    2554                 :            :                 return 1;
    2555                 :          0 :         else if (ucs < e.first)
    2556                 :            :                 return -1;
    2557                 :          0 :         return 0;
    2558                 :            : }
    2559                 :            : 
    2560                 :          3 : static int is_double_width(uint32_t ucs)
    2561                 :            : {
    2562                 :            :         static const struct interval double_width[] = {
    2563                 :            :                 { 0x1100, 0x115F }, { 0x2329, 0x232A }, { 0x2E80, 0x303E },
    2564                 :            :                 { 0x3040, 0xA4CF }, { 0xAC00, 0xD7A3 }, { 0xF900, 0xFAFF },
    2565                 :            :                 { 0xFE10, 0xFE19 }, { 0xFE30, 0xFE6F }, { 0xFF00, 0xFF60 },
    2566                 :            :                 { 0xFFE0, 0xFFE6 }, { 0x20000, 0x2FFFD }, { 0x30000, 0x3FFFD }
    2567                 :            :         };
    2568                 :          3 :         if (ucs < double_width[0].first ||
    2569                 :            :             ucs > double_width[ARRAY_SIZE(double_width) - 1].last)
    2570                 :            :                 return 0;
    2571                 :            : 
    2572                 :          0 :         return bsearch(&ucs, double_width, ARRAY_SIZE(double_width),
    2573                 :          0 :                         sizeof(struct interval), ucs_cmp) != NULL;
    2574                 :            : }
    2575                 :            : 
    2576                 :            : static void con_flush(struct vc_data *vc, unsigned long draw_from,
    2577                 :            :                 unsigned long draw_to, int *draw_x)
    2578                 :            : {
    2579                 :          3 :         if (*draw_x < 0)
    2580                 :            :                 return;
    2581                 :            : 
    2582                 :          0 :         vc->vc_sw->con_putcs(vc, (u16 *)draw_from,
    2583                 :          0 :                         (u16 *)draw_to - (u16 *)draw_from, vc->vc_y, *draw_x);
    2584                 :            :         *draw_x = -1;
    2585                 :            : }
    2586                 :            : 
    2587                 :            : /* acquires console_lock */
    2588                 :          3 : static int do_con_write(struct tty_struct *tty, const unsigned char *buf, int count)
    2589                 :            : {
    2590                 :            :         int c, next_c, tc, ok, n = 0, draw_x = -1;
    2591                 :            :         unsigned int currcons;
    2592                 :            :         unsigned long draw_from = 0, draw_to = 0;
    2593                 :            :         struct vc_data *vc;
    2594                 :            :         unsigned char vc_attr;
    2595                 :            :         struct vt_notifier_param param;
    2596                 :            :         uint8_t rescan;
    2597                 :            :         uint8_t inverse;
    2598                 :            :         uint8_t width;
    2599                 :            :         u16 himask, charmask;
    2600                 :            : 
    2601                 :          3 :         if (in_interrupt())
    2602                 :            :                 return count;
    2603                 :            : 
    2604                 :          3 :         might_sleep();
    2605                 :            : 
    2606                 :          3 :         console_lock();
    2607                 :          3 :         vc = tty->driver_data;
    2608                 :          3 :         if (vc == NULL) {
    2609                 :          0 :                 pr_err("vt: argh, driver_data is NULL !\n");
    2610                 :          0 :                 console_unlock();
    2611                 :          0 :                 return 0;
    2612                 :            :         }
    2613                 :            : 
    2614                 :          3 :         currcons = vc->vc_num;
    2615                 :          3 :         if (!vc_cons_allocated(currcons)) {
    2616                 :            :                 /* could this happen? */
    2617                 :          0 :                 pr_warn_once("con_write: tty %d not allocated\n", currcons+1);
    2618                 :          0 :                 console_unlock();
    2619                 :          0 :                 return 0;
    2620                 :            :         }
    2621                 :            : 
    2622                 :          3 :         himask = vc->vc_hi_font_mask;
    2623                 :          3 :         charmask = himask ? 0x1ff : 0xff;
    2624                 :            : 
    2625                 :            :         /* undraw cursor first */
    2626                 :          3 :         if (con_is_fg(vc))
    2627                 :          3 :                 hide_cursor(vc);
    2628                 :            : 
    2629                 :          3 :         param.vc = vc;
    2630                 :            : 
    2631                 :          3 :         while (!tty->stopped && count) {
    2632                 :          3 :                 int orig = *buf;
    2633                 :            :                 c = orig;
    2634                 :          3 :                 buf++;
    2635                 :          3 :                 n++;
    2636                 :          3 :                 count--;
    2637                 :            :                 rescan = 0;
    2638                 :            :                 inverse = 0;
    2639                 :            :                 width = 1;
    2640                 :            : 
    2641                 :            :                 /* Do no translation at all in control states */
    2642                 :          3 :                 if (vc->vc_state != ESnormal) {
    2643                 :            :                         tc = c;
    2644                 :          3 :                 } else if (vc->vc_utf && !vc->vc_disp_ctrl) {
    2645                 :            :                     /* Combine UTF-8 into Unicode in vc_utf_char.
    2646                 :            :                      * vc_utf_count is the number of continuation bytes still
    2647                 :            :                      * expected to arrive.
    2648                 :            :                      * vc_npar is the number of continuation bytes arrived so
    2649                 :            :                      * far
    2650                 :            :                      */
    2651                 :            : rescan_last_byte:
    2652                 :          3 :                     if ((c & 0xc0) == 0x80) {
    2653                 :            :                         /* Continuation byte received */
    2654                 :            :                         static const uint32_t utf8_length_changes[] = { 0x0000007f, 0x000007ff, 0x0000ffff, 0x001fffff, 0x03ffffff, 0x7fffffff };
    2655                 :          0 :                         if (vc->vc_utf_count) {
    2656                 :          0 :                             vc->vc_utf_char = (vc->vc_utf_char << 6) | (c & 0x3f);
    2657                 :          0 :                             vc->vc_npar++;
    2658                 :          0 :                             if (--vc->vc_utf_count) {
    2659                 :            :                                 /* Still need some bytes */
    2660                 :          0 :                                 continue;
    2661                 :            :                             }
    2662                 :            :                             /* Got a whole character */
    2663                 :            :                             c = vc->vc_utf_char;
    2664                 :            :                             /* Reject overlong sequences */
    2665                 :          0 :                             if (c <= utf8_length_changes[vc->vc_npar - 1] ||
    2666                 :          0 :                                         c > utf8_length_changes[vc->vc_npar])
    2667                 :            :                                 c = 0xfffd;
    2668                 :            :                         } else {
    2669                 :            :                             /* Unexpected continuation byte */
    2670                 :          0 :                             vc->vc_utf_count = 0;
    2671                 :            :                             c = 0xfffd;
    2672                 :            :                         }
    2673                 :            :                     } else {
    2674                 :            :                         /* Single ASCII byte or first byte of a sequence received */
    2675                 :          3 :                         if (vc->vc_utf_count) {
    2676                 :            :                             /* Continuation byte expected */
    2677                 :            :                             rescan = 1;
    2678                 :          0 :                             vc->vc_utf_count = 0;
    2679                 :            :                             c = 0xfffd;
    2680                 :          3 :                         } else if (c > 0x7f) {
    2681                 :            :                             /* First byte of a multibyte sequence received */
    2682                 :          0 :                             vc->vc_npar = 0;
    2683                 :          0 :                             if ((c & 0xe0) == 0xc0) {
    2684                 :          0 :                                 vc->vc_utf_count = 1;
    2685                 :          0 :                                 vc->vc_utf_char = (c & 0x1f);
    2686                 :          0 :                             } else if ((c & 0xf0) == 0xe0) {
    2687                 :          0 :                                 vc->vc_utf_count = 2;
    2688                 :          0 :                                 vc->vc_utf_char = (c & 0x0f);
    2689                 :          0 :                             } else if ((c & 0xf8) == 0xf0) {
    2690                 :          0 :                                 vc->vc_utf_count = 3;
    2691                 :          0 :                                 vc->vc_utf_char = (c & 0x07);
    2692                 :          0 :                             } else if ((c & 0xfc) == 0xf8) {
    2693                 :          0 :                                 vc->vc_utf_count = 4;
    2694                 :          0 :                                 vc->vc_utf_char = (c & 0x03);
    2695                 :          0 :                             } else if ((c & 0xfe) == 0xfc) {
    2696                 :          0 :                                 vc->vc_utf_count = 5;
    2697                 :          0 :                                 vc->vc_utf_char = (c & 0x01);
    2698                 :            :                             } else {
    2699                 :            :                                 /* 254 and 255 are invalid */
    2700                 :            :                                 c = 0xfffd;
    2701                 :            :                             }
    2702                 :          0 :                             if (vc->vc_utf_count) {
    2703                 :            :                                 /* Still need some bytes */
    2704                 :          0 :                                 continue;
    2705                 :            :                             }
    2706                 :            :                         }
    2707                 :            :                         /* Nothing to do if an ASCII byte was received */
    2708                 :            :                     }
    2709                 :            :                     /* End of UTF-8 decoding. */
    2710                 :            :                     /* c is the received character, or U+FFFD for invalid sequences. */
    2711                 :            :                     /* Replace invalid Unicode code points with U+FFFD too */
    2712                 :          3 :                     if ((c >= 0xd800 && c <= 0xdfff) || c == 0xfffe || c == 0xffff)
    2713                 :            :                         c = 0xfffd;
    2714                 :            :                     tc = c;
    2715                 :            :                 } else {        /* no utf or alternate charset mode */
    2716                 :          0 :                     tc = vc_translate(vc, c);
    2717                 :            :                 }
    2718                 :            : 
    2719                 :          3 :                 param.c = tc;
    2720                 :          3 :                 if (atomic_notifier_call_chain(&vt_notifier_list, VT_PREWRITE,
    2721                 :            :                                         &param) == NOTIFY_STOP)
    2722                 :          0 :                         continue;
    2723                 :            : 
    2724                 :            :                 /* If the original code was a control character we
    2725                 :            :                  * only allow a glyph to be displayed if the code is
    2726                 :            :                  * not normally used (such as for cursor movement) or
    2727                 :            :                  * if the disp_ctrl mode has been explicitly enabled.
    2728                 :            :                  * Certain characters (as given by the CTRL_ALWAYS
    2729                 :            :                  * bitmap) are always displayed as control characters,
    2730                 :            :                  * as the console would be pretty useless without
    2731                 :            :                  * them; to display an arbitrary font position use the
    2732                 :            :                  * direct-to-font zone in UTF-8 mode.
    2733                 :            :                  */
    2734                 :          3 :                 ok = tc && (c >= 32 ||
    2735                 :          3 :                             !(vc->vc_disp_ctrl ? (CTRL_ALWAYS >> c) & 1 :
    2736                 :          3 :                                   vc->vc_utf || ((CTRL_ACTION >> c) & 1)))
    2737                 :          3 :                         && (c != 127 || vc->vc_disp_ctrl)
    2738                 :          3 :                         && (c != 128+27);
    2739                 :            : 
    2740                 :          3 :                 if (vc->vc_state == ESnormal && ok) {
    2741                 :          3 :                         if (vc->vc_utf && !vc->vc_disp_ctrl) {
    2742                 :          3 :                                 if (is_double_width(c))
    2743                 :            :                                         width = 2;
    2744                 :            :                         }
    2745                 :            :                         /* Now try to find out how to display it */
    2746                 :          3 :                         tc = conv_uni_to_pc(vc, tc);
    2747                 :          3 :                         if (tc & ~charmask) {
    2748                 :          0 :                                 if (tc == -1 || tc == -2) {
    2749                 :          0 :                                     continue; /* nothing to display */
    2750                 :            :                                 }
    2751                 :            :                                 /* Glyph not found */
    2752                 :          0 :                                 if ((!(vc->vc_utf && !vc->vc_disp_ctrl) || c < 128) && !(c & ~charmask)) {
    2753                 :            :                                     /* In legacy mode use the glyph we get by a 1:1 mapping.
    2754                 :            :                                        This would make absolutely no sense with Unicode in mind,
    2755                 :            :                                        but do this for ASCII characters since a font may lack
    2756                 :            :                                        Unicode mapping info and we don't want to end up with
    2757                 :            :                                        having question marks only. */
    2758                 :            :                                     tc = c;
    2759                 :            :                                 } else {
    2760                 :            :                                     /* Display U+FFFD. If it's not found, display an inverse question mark. */
    2761                 :          0 :                                     tc = conv_uni_to_pc(vc, 0xfffd);
    2762                 :          0 :                                     if (tc < 0) {
    2763                 :            :                                         inverse = 1;
    2764                 :          0 :                                         tc = conv_uni_to_pc(vc, '?');
    2765                 :          0 :                                         if (tc < 0) tc = '?';
    2766                 :            :                                     }
    2767                 :            :                                 }
    2768                 :            :                         }
    2769                 :            : 
    2770                 :          3 :                         if (!inverse) {
    2771                 :          3 :                                 vc_attr = vc->vc_attr;
    2772                 :            :                         } else {
    2773                 :            :                                 /* invert vc_attr */
    2774                 :          0 :                                 if (!vc->vc_can_do_color) {
    2775                 :          0 :                                         vc_attr = (vc->vc_attr) ^ 0x08;
    2776                 :          0 :                                 } else if (vc->vc_hi_font_mask == 0x100) {
    2777                 :          0 :                                         vc_attr = ((vc->vc_attr) & 0x11) | (((vc->vc_attr) & 0xe0) >> 4) | (((vc->vc_attr) & 0x0e) << 4);
    2778                 :            :                                 } else {
    2779                 :          0 :                                         vc_attr = ((vc->vc_attr) & 0x88) | (((vc->vc_attr) & 0x70) >> 4) | (((vc->vc_attr) & 0x07) << 4);
    2780                 :            :                                 }
    2781                 :            :                                 con_flush(vc, draw_from, draw_to, &draw_x);
    2782                 :            :                         }
    2783                 :            : 
    2784                 :            :                         next_c = c;
    2785                 :            :                         while (1) {
    2786                 :          3 :                                 if (vc->vc_need_wrap || vc->vc_decim)
    2787                 :            :                                         con_flush(vc, draw_from, draw_to,
    2788                 :            :                                                         &draw_x);
    2789                 :          3 :                                 if (vc->vc_need_wrap) {
    2790                 :          0 :                                         cr(vc);
    2791                 :          0 :                                         lf(vc);
    2792                 :            :                                 }
    2793                 :          3 :                                 if (vc->vc_decim)
    2794                 :          0 :                                         insert_char(vc, 1);
    2795                 :          3 :                                 vc_uniscr_putc(vc, next_c);
    2796                 :          3 :                                 scr_writew(himask ?
    2797                 :            :                                              ((vc_attr << 8) & ~himask) + ((tc & 0x100) ? himask : 0) + (tc & 0xff) :
    2798                 :            :                                              (vc_attr << 8) + tc,
    2799                 :            :                                            (u16 *) vc->vc_pos);
    2800                 :          3 :                                 if (con_should_update(vc) && draw_x < 0) {
    2801                 :          0 :                                         draw_x = vc->vc_x;
    2802                 :          0 :                                         draw_from = vc->vc_pos;
    2803                 :            :                                 }
    2804                 :          3 :                                 if (vc->vc_x == vc->vc_cols - 1) {
    2805                 :          0 :                                         vc->vc_need_wrap = vc->vc_decawm;
    2806                 :          0 :                                         draw_to = vc->vc_pos + 2;
    2807                 :            :                                 } else {
    2808                 :          3 :                                         vc->vc_x++;
    2809                 :          3 :                                         draw_to = (vc->vc_pos += 2);
    2810                 :            :                                 }
    2811                 :            : 
    2812                 :          3 :                                 if (!--width) break;
    2813                 :            : 
    2814                 :          0 :                                 tc = conv_uni_to_pc(vc, ' '); /* A space is printed in the second column */
    2815                 :          0 :                                 if (tc < 0) tc = ' ';
    2816                 :            :                                 next_c = ' ';
    2817                 :            :                         }
    2818                 :          3 :                         notify_write(vc, c);
    2819                 :            : 
    2820                 :          3 :                         if (inverse)
    2821                 :            :                                 con_flush(vc, draw_from, draw_to, &draw_x);
    2822                 :            : 
    2823                 :          3 :                         if (rescan) {
    2824                 :            :                                 rescan = 0;
    2825                 :            :                                 inverse = 0;
    2826                 :            :                                 width = 1;
    2827                 :            :                                 c = orig;
    2828                 :            :                                 goto rescan_last_byte;
    2829                 :            :                         }
    2830                 :          3 :                         continue;
    2831                 :            :                 }
    2832                 :            :                 con_flush(vc, draw_from, draw_to, &draw_x);
    2833                 :          3 :                 do_con_trol(tty, vc, orig);
    2834                 :            :         }
    2835                 :            :         con_flush(vc, draw_from, draw_to, &draw_x);
    2836                 :            :         vc_uniscr_debug_check(vc);
    2837                 :          3 :         console_conditional_schedule();
    2838                 :            :         notify_update(vc);
    2839                 :          3 :         console_unlock();
    2840                 :          3 :         return n;
    2841                 :            : }
    2842                 :            : 
    2843                 :            : /*
    2844                 :            :  * This is the console switching callback.
    2845                 :            :  *
    2846                 :            :  * Doing console switching in a process context allows
    2847                 :            :  * us to do the switches asynchronously (needed when we want
    2848                 :            :  * to switch due to a keyboard interrupt).  Synchronization
    2849                 :            :  * with other console code and prevention of re-entrancy is
    2850                 :            :  * ensured with console_lock.
    2851                 :            :  */
    2852                 :          3 : static void console_callback(struct work_struct *ignored)
    2853                 :            : {
    2854                 :          3 :         console_lock();
    2855                 :            : 
    2856                 :          3 :         if (want_console >= 0) {
    2857                 :          3 :                 if (want_console != fg_console &&
    2858                 :          3 :                     vc_cons_allocated(want_console)) {
    2859                 :          3 :                         hide_cursor(vc_cons[fg_console].d);
    2860                 :          3 :                         change_console(vc_cons[want_console].d);
    2861                 :            :                         /* we only changed when the console had already
    2862                 :            :                            been allocated - a new console is not created
    2863                 :            :                            in an interrupt routine */
    2864                 :            :                 }
    2865                 :          3 :                 want_console = -1;
    2866                 :            :         }
    2867                 :          3 :         if (do_poke_blanked_console) { /* do not unblank for a LED change */
    2868                 :          3 :                 do_poke_blanked_console = 0;
    2869                 :          3 :                 poke_blanked_console();
    2870                 :            :         }
    2871                 :          3 :         if (scrollback_delta) {
    2872                 :          0 :                 struct vc_data *vc = vc_cons[fg_console].d;
    2873                 :          0 :                 clear_selection();
    2874                 :          0 :                 if (vc->vc_mode == KD_TEXT && vc->vc_sw->con_scrolldelta)
    2875                 :          0 :                         vc->vc_sw->con_scrolldelta(vc, scrollback_delta);
    2876                 :          0 :                 scrollback_delta = 0;
    2877                 :            :         }
    2878                 :          3 :         if (blank_timer_expired) {
    2879                 :          0 :                 do_blank_screen(0);
    2880                 :          0 :                 blank_timer_expired = 0;
    2881                 :            :         }
    2882                 :          3 :         notify_update(vc_cons[fg_console].d);
    2883                 :            : 
    2884                 :          3 :         console_unlock();
    2885                 :          3 : }
    2886                 :            : 
    2887                 :          3 : int set_console(int nr)
    2888                 :            : {
    2889                 :          3 :         struct vc_data *vc = vc_cons[fg_console].d;
    2890                 :            : 
    2891                 :          3 :         if (!vc_cons_allocated(nr) || vt_dont_switch ||
    2892                 :          3 :                 (vc->vt_mode.mode == VT_AUTO && vc->vc_mode == KD_GRAPHICS)) {
    2893                 :            : 
    2894                 :            :                 /*
    2895                 :            :                  * Console switch will fail in console_callback() or
    2896                 :            :                  * change_console() so there is no point scheduling
    2897                 :            :                  * the callback
    2898                 :            :                  *
    2899                 :            :                  * Existing set_console() users don't check the return
    2900                 :            :                  * value so this shouldn't break anything
    2901                 :            :                  */
    2902                 :            :                 return -EINVAL;
    2903                 :            :         }
    2904                 :            : 
    2905                 :          3 :         want_console = nr;
    2906                 :            :         schedule_console_callback();
    2907                 :            : 
    2908                 :          3 :         return 0;
    2909                 :            : }
    2910                 :            : 
    2911                 :            : struct tty_driver *console_driver;
    2912                 :            : 
    2913                 :            : #ifdef CONFIG_VT_CONSOLE
    2914                 :            : 
    2915                 :            : /**
    2916                 :            :  * vt_kmsg_redirect() - Sets/gets the kernel message console
    2917                 :            :  * @new:        The new virtual terminal number or -1 if the console should stay
    2918                 :            :  *              unchanged
    2919                 :            :  *
    2920                 :            :  * By default, the kernel messages are always printed on the current virtual
    2921                 :            :  * console. However, the user may modify that default with the
    2922                 :            :  * TIOCL_SETKMSGREDIRECT ioctl call.
    2923                 :            :  *
    2924                 :            :  * This function sets the kernel message console to be @new. It returns the old
    2925                 :            :  * virtual console number. The virtual terminal number 0 (both as parameter and
    2926                 :            :  * return value) means no redirection (i.e. always printed on the currently
    2927                 :            :  * active console).
    2928                 :            :  *
    2929                 :            :  * The parameter -1 means that only the current console is returned, but the
    2930                 :            :  * value is not modified. You may use the macro vt_get_kmsg_redirect() in that
    2931                 :            :  * case to make the code more understandable.
    2932                 :            :  *
    2933                 :            :  * When the kernel is compiled without CONFIG_VT_CONSOLE, this function ignores
    2934                 :            :  * the parameter and always returns 0.
    2935                 :            :  */
    2936                 :          0 : int vt_kmsg_redirect(int new)
    2937                 :            : {
    2938                 :            :         static int kmsg_con;
    2939                 :            : 
    2940                 :          0 :         if (new != -1)
    2941                 :          0 :                 return xchg(&kmsg_con, new);
    2942                 :            :         else
    2943                 :          0 :                 return kmsg_con;
    2944                 :            : }
    2945                 :            : 
    2946                 :            : /*
    2947                 :            :  *      Console on virtual terminal
    2948                 :            :  *
    2949                 :            :  * The console must be locked when we get here.
    2950                 :            :  */
    2951                 :            : 
    2952                 :          0 : static void vt_console_print(struct console *co, const char *b, unsigned count)
    2953                 :            : {
    2954                 :          0 :         struct vc_data *vc = vc_cons[fg_console].d;
    2955                 :            :         unsigned char c;
    2956                 :            :         static DEFINE_SPINLOCK(printing_lock);
    2957                 :            :         const ushort *start;
    2958                 :            :         ushort start_x, cnt;
    2959                 :            :         int kmsg_console;
    2960                 :            : 
    2961                 :            :         /* console busy or not yet initialized */
    2962                 :          0 :         if (!printable)
    2963                 :            :                 return;
    2964                 :          0 :         if (!spin_trylock(&printing_lock))
    2965                 :            :                 return;
    2966                 :            : 
    2967                 :          0 :         kmsg_console = vt_get_kmsg_redirect();
    2968                 :          0 :         if (kmsg_console && vc_cons_allocated(kmsg_console - 1))
    2969                 :          0 :                 vc = vc_cons[kmsg_console - 1].d;
    2970                 :            : 
    2971                 :          0 :         if (!vc_cons_allocated(fg_console)) {
    2972                 :            :                 /* impossible */
    2973                 :            :                 /* printk("vt_console_print: tty %d not allocated ??\n", currcons+1); */
    2974                 :            :                 goto quit;
    2975                 :            :         }
    2976                 :            : 
    2977                 :          0 :         if (vc->vc_mode != KD_TEXT)
    2978                 :            :                 goto quit;
    2979                 :            : 
    2980                 :            :         /* undraw cursor first */
    2981                 :          0 :         if (con_is_fg(vc))
    2982                 :          0 :                 hide_cursor(vc);
    2983                 :            : 
    2984                 :          0 :         start = (ushort *)vc->vc_pos;
    2985                 :          0 :         start_x = vc->vc_x;
    2986                 :            :         cnt = 0;
    2987                 :          0 :         while (count--) {
    2988                 :          0 :                 c = *b++;
    2989                 :          0 :                 if (c == 10 || c == 13 || c == 8 || vc->vc_need_wrap) {
    2990                 :          0 :                         if (cnt && con_is_visible(vc))
    2991                 :          0 :                                 vc->vc_sw->con_putcs(vc, start, cnt, vc->vc_y, start_x);
    2992                 :            :                         cnt = 0;
    2993                 :          0 :                         if (c == 8) {           /* backspace */
    2994                 :          0 :                                 bs(vc);
    2995                 :          0 :                                 start = (ushort *)vc->vc_pos;
    2996                 :          0 :                                 start_x = vc->vc_x;
    2997                 :          0 :                                 continue;
    2998                 :            :                         }
    2999                 :          0 :                         if (c != 13)
    3000                 :          0 :                                 lf(vc);
    3001                 :          0 :                         cr(vc);
    3002                 :          0 :                         start = (ushort *)vc->vc_pos;
    3003                 :          0 :                         start_x = vc->vc_x;
    3004                 :          0 :                         if (c == 10 || c == 13)
    3005                 :          0 :                                 continue;
    3006                 :            :                 }
    3007                 :          0 :                 vc_uniscr_putc(vc, c);
    3008                 :          0 :                 scr_writew((vc->vc_attr << 8) + c, (unsigned short *)vc->vc_pos);
    3009                 :            :                 notify_write(vc, c);
    3010                 :          0 :                 cnt++;
    3011                 :          0 :                 if (vc->vc_x == vc->vc_cols - 1) {
    3012                 :          0 :                         vc->vc_need_wrap = 1;
    3013                 :            :                 } else {
    3014                 :          0 :                         vc->vc_pos += 2;
    3015                 :          0 :                         vc->vc_x++;
    3016                 :            :                 }
    3017                 :            :         }
    3018                 :          0 :         if (cnt && con_is_visible(vc))
    3019                 :          0 :                 vc->vc_sw->con_putcs(vc, start, cnt, vc->vc_y, start_x);
    3020                 :          0 :         set_cursor(vc);
    3021                 :            :         notify_update(vc);
    3022                 :            : 
    3023                 :            : quit:
    3024                 :            :         spin_unlock(&printing_lock);
    3025                 :            : }
    3026                 :            : 
    3027                 :          2 : static struct tty_driver *vt_console_device(struct console *c, int *index)
    3028                 :            : {
    3029                 :          2 :         *index = c->index ? c->index-1 : fg_console;
    3030                 :          2 :         return console_driver;
    3031                 :            : }
    3032                 :            : 
    3033                 :            : static struct console vt_console_driver = {
    3034                 :            :         .name           = "tty",
    3035                 :            :         .write          = vt_console_print,
    3036                 :            :         .device         = vt_console_device,
    3037                 :            :         .unblank        = unblank_screen,
    3038                 :            :         .flags          = CON_PRINTBUFFER,
    3039                 :            :         .index          = -1,
    3040                 :            : };
    3041                 :            : #endif
    3042                 :            : 
    3043                 :            : /*
    3044                 :            :  *      Handling of Linux-specific VC ioctls
    3045                 :            :  */
    3046                 :            : 
    3047                 :            : /*
    3048                 :            :  * Generally a bit racy with respect to console_lock();.
    3049                 :            :  *
    3050                 :            :  * There are some functions which don't need it.
    3051                 :            :  *
    3052                 :            :  * There are some functions which can sleep for arbitrary periods
    3053                 :            :  * (paste_selection) but we don't need the lock there anyway.
    3054                 :            :  *
    3055                 :            :  * set_selection_user has locking, and definitely needs it
    3056                 :            :  */
    3057                 :            : 
    3058                 :          0 : int tioclinux(struct tty_struct *tty, unsigned long arg)
    3059                 :            : {
    3060                 :            :         char type, data;
    3061                 :          0 :         char __user *p = (char __user *)arg;
    3062                 :            :         int lines;
    3063                 :            :         int ret;
    3064                 :            : 
    3065                 :          0 :         if (current->signal->tty != tty && !capable(CAP_SYS_ADMIN))
    3066                 :            :                 return -EPERM;
    3067                 :          0 :         if (get_user(type, p))
    3068                 :            :                 return -EFAULT;
    3069                 :            :         ret = 0;
    3070                 :            : 
    3071                 :          0 :         switch (type)
    3072                 :            :         {
    3073                 :            :                 case TIOCL_SETSEL:
    3074                 :          0 :                         ret = set_selection_user((struct tiocl_selection
    3075                 :            :                                                  __user *)(p+1), tty);
    3076                 :          0 :                         break;
    3077                 :            :                 case TIOCL_PASTESEL:
    3078                 :          0 :                         ret = paste_selection(tty);
    3079                 :          0 :                         break;
    3080                 :            :                 case TIOCL_UNBLANKSCREEN:
    3081                 :          0 :                         console_lock();
    3082                 :            :                         unblank_screen();
    3083                 :          0 :                         console_unlock();
    3084                 :          0 :                         break;
    3085                 :            :                 case TIOCL_SELLOADLUT:
    3086                 :          0 :                         console_lock();
    3087                 :          0 :                         ret = sel_loadlut(p);
    3088                 :          0 :                         console_unlock();
    3089                 :          0 :                         break;
    3090                 :            :                 case TIOCL_GETSHIFTSTATE:
    3091                 :            : 
    3092                 :            :         /*
    3093                 :            :          * Make it possible to react to Shift+Mousebutton.
    3094                 :            :          * Note that 'shift_state' is an undocumented
    3095                 :            :          * kernel-internal variable; programs not closely
    3096                 :            :          * related to the kernel should not use this.
    3097                 :            :          */
    3098                 :          0 :                         data = vt_get_shift_state();
    3099                 :          0 :                         ret = put_user(data, p);
    3100                 :          0 :                         break;
    3101                 :            :                 case TIOCL_GETMOUSEREPORTING:
    3102                 :          0 :                         console_lock(); /* May be overkill */
    3103                 :          0 :                         data = mouse_reporting();
    3104                 :          0 :                         console_unlock();
    3105                 :          0 :                         ret = put_user(data, p);
    3106                 :          0 :                         break;
    3107                 :            :                 case TIOCL_SETVESABLANK:
    3108                 :          0 :                         console_lock();
    3109                 :          0 :                         ret = set_vesa_blanking(p);
    3110                 :          0 :                         console_unlock();
    3111                 :          0 :                         break;
    3112                 :            :                 case TIOCL_GETKMSGREDIRECT:
    3113                 :          0 :                         data = vt_get_kmsg_redirect();
    3114                 :          0 :                         ret = put_user(data, p);
    3115                 :          0 :                         break;
    3116                 :            :                 case TIOCL_SETKMSGREDIRECT:
    3117                 :          0 :                         if (!capable(CAP_SYS_ADMIN)) {
    3118                 :            :                                 ret = -EPERM;
    3119                 :            :                         } else {
    3120                 :          0 :                                 if (get_user(data, p+1))
    3121                 :            :                                         ret = -EFAULT;
    3122                 :            :                                 else
    3123                 :          0 :                                         vt_kmsg_redirect(data);
    3124                 :            :                         }
    3125                 :            :                         break;
    3126                 :            :                 case TIOCL_GETFGCONSOLE:
    3127                 :            :                         /* No locking needed as this is a transiently
    3128                 :            :                            correct return anyway if the caller hasn't
    3129                 :            :                            disabled switching */
    3130                 :          0 :                         ret = fg_console;
    3131                 :          0 :                         break;
    3132                 :            :                 case TIOCL_SCROLLCONSOLE:
    3133                 :          0 :                         if (get_user(lines, (s32 __user *)(p+4))) {
    3134                 :            :                                 ret = -EFAULT;
    3135                 :            :                         } else {
    3136                 :            :                                 /* Need the console lock here. Note that lots
    3137                 :            :                                    of other calls need fixing before the lock
    3138                 :            :                                    is actually useful ! */
    3139                 :          0 :                                 console_lock();
    3140                 :          0 :                                 scrollfront(vc_cons[fg_console].d, lines);
    3141                 :          0 :                                 console_unlock();
    3142                 :            :                                 ret = 0;
    3143                 :            :                         }
    3144                 :            :                         break;
    3145                 :            :                 case TIOCL_BLANKSCREEN: /* until explicitly unblanked, not only poked */
    3146                 :          0 :                         console_lock();
    3147                 :          0 :                         ignore_poke = 1;
    3148                 :          0 :                         do_blank_screen(0);
    3149                 :          0 :                         console_unlock();
    3150                 :          0 :                         break;
    3151                 :            :                 case TIOCL_BLANKEDSCREEN:
    3152                 :          0 :                         ret = console_blanked;
    3153                 :          0 :                         break;
    3154                 :            :                 default:
    3155                 :            :                         ret = -EINVAL;
    3156                 :            :                         break;
    3157                 :            :         }
    3158                 :          0 :         return ret;
    3159                 :            : }
    3160                 :            : 
    3161                 :            : /*
    3162                 :            :  * /dev/ttyN handling
    3163                 :            :  */
    3164                 :            : 
    3165                 :          3 : static int con_write(struct tty_struct *tty, const unsigned char *buf, int count)
    3166                 :            : {
    3167                 :            :         int     retval;
    3168                 :            : 
    3169                 :          3 :         retval = do_con_write(tty, buf, count);
    3170                 :          3 :         con_flush_chars(tty);
    3171                 :            : 
    3172                 :          3 :         return retval;
    3173                 :            : }
    3174                 :            : 
    3175                 :          0 : static int con_put_char(struct tty_struct *tty, unsigned char ch)
    3176                 :            : {
    3177                 :          0 :         if (in_interrupt())
    3178                 :            :                 return 0;       /* n_r3964 calls put_char() from interrupt context */
    3179                 :          0 :         return do_con_write(tty, &ch, 1);
    3180                 :            : }
    3181                 :            : 
    3182                 :          3 : static int con_write_room(struct tty_struct *tty)
    3183                 :            : {
    3184                 :          3 :         if (tty->stopped)
    3185                 :            :                 return 0;
    3186                 :          3 :         return 32768;           /* No limit, really; we're not buffering */
    3187                 :            : }
    3188                 :            : 
    3189                 :          3 : static int con_chars_in_buffer(struct tty_struct *tty)
    3190                 :            : {
    3191                 :          3 :         return 0;               /* we're not buffering */
    3192                 :            : }
    3193                 :            : 
    3194                 :            : /*
    3195                 :            :  * con_throttle and con_unthrottle are only used for
    3196                 :            :  * paste_selection(), which has to stuff in a large number of
    3197                 :            :  * characters...
    3198                 :            :  */
    3199                 :          0 : static void con_throttle(struct tty_struct *tty)
    3200                 :            : {
    3201                 :          0 : }
    3202                 :            : 
    3203                 :          0 : static void con_unthrottle(struct tty_struct *tty)
    3204                 :            : {
    3205                 :          0 :         struct vc_data *vc = tty->driver_data;
    3206                 :            : 
    3207                 :          0 :         wake_up_interruptible(&vc->paste_wait);
    3208                 :          0 : }
    3209                 :            : 
    3210                 :            : /*
    3211                 :            :  * Turn the Scroll-Lock LED on when the tty is stopped
    3212                 :            :  */
    3213                 :          0 : static void con_stop(struct tty_struct *tty)
    3214                 :            : {
    3215                 :            :         int console_num;
    3216                 :          0 :         if (!tty)
    3217                 :            :                 return;
    3218                 :          0 :         console_num = tty->index;
    3219                 :          0 :         if (!vc_cons_allocated(console_num))
    3220                 :            :                 return;
    3221                 :          0 :         vt_kbd_con_stop(console_num);
    3222                 :            : }
    3223                 :            : 
    3224                 :            : /*
    3225                 :            :  * Turn the Scroll-Lock LED off when the console is started
    3226                 :            :  */
    3227                 :          0 : static void con_start(struct tty_struct *tty)
    3228                 :            : {
    3229                 :            :         int console_num;
    3230                 :          0 :         if (!tty)
    3231                 :            :                 return;
    3232                 :          0 :         console_num = tty->index;
    3233                 :          0 :         if (!vc_cons_allocated(console_num))
    3234                 :            :                 return;
    3235                 :          0 :         vt_kbd_con_start(console_num);
    3236                 :            : }
    3237                 :            : 
    3238                 :          3 : static void con_flush_chars(struct tty_struct *tty)
    3239                 :            : {
    3240                 :            :         struct vc_data *vc;
    3241                 :            : 
    3242                 :          3 :         if (in_interrupt())     /* from flush_to_ldisc */
    3243                 :          3 :                 return;
    3244                 :            : 
    3245                 :            :         /* if we race with con_close(), vt may be null */
    3246                 :          3 :         console_lock();
    3247                 :          3 :         vc = tty->driver_data;
    3248                 :          3 :         if (vc)
    3249                 :          3 :                 set_cursor(vc);
    3250                 :          3 :         console_unlock();
    3251                 :            : }
    3252                 :            : 
    3253                 :            : /*
    3254                 :            :  * Allocate the console screen memory.
    3255                 :            :  */
    3256                 :          3 : static int con_install(struct tty_driver *driver, struct tty_struct *tty)
    3257                 :            : {
    3258                 :          3 :         unsigned int currcons = tty->index;
    3259                 :            :         struct vc_data *vc;
    3260                 :            :         int ret;
    3261                 :            : 
    3262                 :          3 :         console_lock();
    3263                 :          3 :         ret = vc_allocate(currcons);
    3264                 :          3 :         if (ret)
    3265                 :            :                 goto unlock;
    3266                 :            : 
    3267                 :          3 :         vc = vc_cons[currcons].d;
    3268                 :            : 
    3269                 :            :         /* Still being freed */
    3270                 :          3 :         if (vc->port.tty) {
    3271                 :            :                 ret = -ERESTARTSYS;
    3272                 :            :                 goto unlock;
    3273                 :            :         }
    3274                 :            : 
    3275                 :          3 :         ret = tty_port_install(&vc->port, driver, tty);
    3276                 :          3 :         if (ret)
    3277                 :            :                 goto unlock;
    3278                 :            : 
    3279                 :          3 :         tty->driver_data = vc;
    3280                 :          3 :         vc->port.tty = tty;
    3281                 :            :         tty_port_get(&vc->port);
    3282                 :            : 
    3283                 :          3 :         if (!tty->winsize.ws_row && !tty->winsize.ws_col) {
    3284                 :          3 :                 tty->winsize.ws_row = vc_cons[currcons].d->vc_rows;
    3285                 :          3 :                 tty->winsize.ws_col = vc_cons[currcons].d->vc_cols;
    3286                 :            :         }
    3287                 :          3 :         if (vc->vc_utf)
    3288                 :          3 :                 tty->termios.c_iflag |= IUTF8;
    3289                 :            :         else
    3290                 :          0 :                 tty->termios.c_iflag &= ~IUTF8;
    3291                 :            : unlock:
    3292                 :          3 :         console_unlock();
    3293                 :          3 :         return ret;
    3294                 :            : }
    3295                 :            : 
    3296                 :          3 : static int con_open(struct tty_struct *tty, struct file *filp)
    3297                 :            : {
    3298                 :            :         /* everything done in install */
    3299                 :          3 :         return 0;
    3300                 :            : }
    3301                 :            : 
    3302                 :            : 
    3303                 :          3 : static void con_close(struct tty_struct *tty, struct file *filp)
    3304                 :            : {
    3305                 :            :         /* Nothing to do - we defer to shutdown */
    3306                 :          3 : }
    3307                 :            : 
    3308                 :          3 : static void con_shutdown(struct tty_struct *tty)
    3309                 :            : {
    3310                 :          3 :         struct vc_data *vc = tty->driver_data;
    3311                 :          3 :         BUG_ON(vc == NULL);
    3312                 :          3 :         console_lock();
    3313                 :          3 :         vc->port.tty = NULL;
    3314                 :          3 :         console_unlock();
    3315                 :          3 : }
    3316                 :            : 
    3317                 :          3 : static void con_cleanup(struct tty_struct *tty)
    3318                 :            : {
    3319                 :          3 :         struct vc_data *vc = tty->driver_data;
    3320                 :            : 
    3321                 :          3 :         tty_port_put(&vc->port);
    3322                 :          3 : }
    3323                 :            : 
    3324                 :            : static int default_color           = 7; /* white */
    3325                 :            : static int default_italic_color    = 2; // green (ASCII)
    3326                 :            : static int default_underline_color = 3; // cyan (ASCII)
    3327                 :            : module_param_named(color, default_color, int, S_IRUGO | S_IWUSR);
    3328                 :            : module_param_named(italic, default_italic_color, int, S_IRUGO | S_IWUSR);
    3329                 :            : module_param_named(underline, default_underline_color, int, S_IRUGO | S_IWUSR);
    3330                 :            : 
    3331                 :          3 : static void vc_init(struct vc_data *vc, unsigned int rows,
    3332                 :            :                     unsigned int cols, int do_clear)
    3333                 :            : {
    3334                 :            :         int j, k ;
    3335                 :            : 
    3336                 :          3 :         vc->vc_cols = cols;
    3337                 :          3 :         vc->vc_rows = rows;
    3338                 :          3 :         vc->vc_size_row = cols << 1;
    3339                 :          3 :         vc->vc_screenbuf_size = vc->vc_rows * vc->vc_size_row;
    3340                 :            : 
    3341                 :          3 :         set_origin(vc);
    3342                 :          3 :         vc->vc_pos = vc->vc_origin;
    3343                 :          3 :         reset_vc(vc);
    3344                 :          3 :         for (j=k=0; j<16; j++) {
    3345                 :          3 :                 vc->vc_palette[k++] = default_red[j] ;
    3346                 :          3 :                 vc->vc_palette[k++] = default_grn[j] ;
    3347                 :          3 :                 vc->vc_palette[k++] = default_blu[j] ;
    3348                 :            :         }
    3349                 :          3 :         vc->vc_def_color       = default_color;
    3350                 :          3 :         vc->vc_ulcolor         = default_underline_color;
    3351                 :          3 :         vc->vc_itcolor         = default_italic_color;
    3352                 :          3 :         vc->vc_halfcolor       = 0x08;   /* grey */
    3353                 :          3 :         init_waitqueue_head(&vc->paste_wait);
    3354                 :          3 :         reset_terminal(vc, do_clear);
    3355                 :          3 : }
    3356                 :            : 
    3357                 :            : /*
    3358                 :            :  * This routine initializes console interrupts, and does nothing
    3359                 :            :  * else. If you want the screen to clear, call tty_write with
    3360                 :            :  * the appropriate escape-sequence.
    3361                 :            :  */
    3362                 :            : 
    3363                 :          3 : static int __init con_init(void)
    3364                 :            : {
    3365                 :            :         const char *display_desc = NULL;
    3366                 :            :         struct vc_data *vc;
    3367                 :            :         unsigned int currcons = 0, i;
    3368                 :            : 
    3369                 :          3 :         console_lock();
    3370                 :            : 
    3371                 :          3 :         if (conswitchp)
    3372                 :          3 :                 display_desc = conswitchp->con_startup();
    3373                 :          3 :         if (!display_desc) {
    3374                 :          0 :                 fg_console = 0;
    3375                 :          0 :                 console_unlock();
    3376                 :          0 :                 return 0;
    3377                 :            :         }
    3378                 :            : 
    3379                 :          0 :         for (i = 0; i < MAX_NR_CON_DRIVER; i++) {
    3380                 :            :                 struct con_driver *con_driver = &registered_con_driver[i];
    3381                 :            : 
    3382                 :          3 :                 if (con_driver->con == NULL) {
    3383                 :          3 :                         con_driver->con = conswitchp;
    3384                 :          3 :                         con_driver->desc = display_desc;
    3385                 :          3 :                         con_driver->flag = CON_DRIVER_FLAG_INIT;
    3386                 :          3 :                         con_driver->first = 0;
    3387                 :          3 :                         con_driver->last = MAX_NR_CONSOLES - 1;
    3388                 :          3 :                         break;
    3389                 :            :                 }
    3390                 :            :         }
    3391                 :            : 
    3392                 :          3 :         for (i = 0; i < MAX_NR_CONSOLES; i++)
    3393                 :          3 :                 con_driver_map[i] = conswitchp;
    3394                 :            : 
    3395                 :          3 :         if (blankinterval) {
    3396                 :          0 :                 blank_state = blank_normal_wait;
    3397                 :          0 :                 mod_timer(&console_timer, jiffies + (blankinterval * HZ));
    3398                 :            :         }
    3399                 :            : 
    3400                 :          3 :         for (currcons = 0; currcons < MIN_NR_CONSOLES; currcons++) {
    3401                 :          3 :                 vc_cons[currcons].d = vc = kzalloc(sizeof(struct vc_data), GFP_NOWAIT);
    3402                 :          3 :                 INIT_WORK(&vc_cons[currcons].SAK_work, vc_SAK);
    3403                 :          3 :                 tty_port_init(&vc->port);
    3404                 :          3 :                 visual_init(vc, currcons, 1);
    3405                 :            :                 /* Assuming vc->vc_{cols,rows,screenbuf_size} are sane here. */
    3406                 :          3 :                 vc->vc_screenbuf = kzalloc(vc->vc_screenbuf_size, GFP_NOWAIT);
    3407                 :          3 :                 vc_init(vc, vc->vc_rows, vc->vc_cols,
    3408                 :          3 :                         currcons || !vc->vc_sw->con_save_screen);
    3409                 :            :         }
    3410                 :          3 :         currcons = fg_console = 0;
    3411                 :          3 :         master_display_fg = vc = vc_cons[currcons].d;
    3412                 :          3 :         set_origin(vc);
    3413                 :          3 :         save_screen(vc);
    3414                 :          3 :         gotoxy(vc, vc->vc_x, vc->vc_y);
    3415                 :          3 :         csi_J(vc, 0);
    3416                 :          3 :         update_screen(vc);
    3417                 :          3 :         pr_info("Console: %s %s %dx%d\n",
    3418                 :            :                 vc->vc_can_do_color ? "colour" : "mono",
    3419                 :            :                 display_desc, vc->vc_cols, vc->vc_rows);
    3420                 :          3 :         printable = 1;
    3421                 :            : 
    3422                 :          3 :         console_unlock();
    3423                 :            : 
    3424                 :            : #ifdef CONFIG_VT_CONSOLE
    3425                 :          3 :         register_console(&vt_console_driver);
    3426                 :            : #endif
    3427                 :          3 :         return 0;
    3428                 :            : }
    3429                 :            : console_initcall(con_init);
    3430                 :            : 
    3431                 :            : static const struct tty_operations con_ops = {
    3432                 :            :         .install = con_install,
    3433                 :            :         .open = con_open,
    3434                 :            :         .close = con_close,
    3435                 :            :         .write = con_write,
    3436                 :            :         .write_room = con_write_room,
    3437                 :            :         .put_char = con_put_char,
    3438                 :            :         .flush_chars = con_flush_chars,
    3439                 :            :         .chars_in_buffer = con_chars_in_buffer,
    3440                 :            :         .ioctl = vt_ioctl,
    3441                 :            : #ifdef CONFIG_COMPAT
    3442                 :            :         .compat_ioctl = vt_compat_ioctl,
    3443                 :            : #endif
    3444                 :            :         .stop = con_stop,
    3445                 :            :         .start = con_start,
    3446                 :            :         .throttle = con_throttle,
    3447                 :            :         .unthrottle = con_unthrottle,
    3448                 :            :         .resize = vt_resize,
    3449                 :            :         .shutdown = con_shutdown,
    3450                 :            :         .cleanup = con_cleanup,
    3451                 :            : };
    3452                 :            : 
    3453                 :            : static struct cdev vc0_cdev;
    3454                 :            : 
    3455                 :          3 : static ssize_t show_tty_active(struct device *dev,
    3456                 :            :                                 struct device_attribute *attr, char *buf)
    3457                 :            : {
    3458                 :          3 :         return sprintf(buf, "tty%d\n", fg_console + 1);
    3459                 :            : }
    3460                 :            : static DEVICE_ATTR(active, S_IRUGO, show_tty_active, NULL);
    3461                 :            : 
    3462                 :            : static struct attribute *vt_dev_attrs[] = {
    3463                 :            :         &dev_attr_active.attr,
    3464                 :            :         NULL
    3465                 :            : };
    3466                 :            : 
    3467                 :            : ATTRIBUTE_GROUPS(vt_dev);
    3468                 :            : 
    3469                 :          3 : int __init vty_init(const struct file_operations *console_fops)
    3470                 :            : {
    3471                 :          3 :         cdev_init(&vc0_cdev, console_fops);
    3472                 :          3 :         if (cdev_add(&vc0_cdev, MKDEV(TTY_MAJOR, 0), 1) ||
    3473                 :          3 :             register_chrdev_region(MKDEV(TTY_MAJOR, 0), 1, "/dev/vc/0") < 0)
    3474                 :          0 :                 panic("Couldn't register /dev/tty0 driver\n");
    3475                 :          3 :         tty0dev = device_create_with_groups(tty_class, NULL,
    3476                 :            :                                             MKDEV(TTY_MAJOR, 0), NULL,
    3477                 :            :                                             vt_dev_groups, "tty0");
    3478                 :          3 :         if (IS_ERR(tty0dev))
    3479                 :          0 :                 tty0dev = NULL;
    3480                 :            : 
    3481                 :          3 :         vcs_init();
    3482                 :            : 
    3483                 :          3 :         console_driver = alloc_tty_driver(MAX_NR_CONSOLES);
    3484                 :          3 :         if (!console_driver)
    3485                 :          0 :                 panic("Couldn't allocate console driver\n");
    3486                 :            : 
    3487                 :          3 :         console_driver->name = "tty";
    3488                 :          3 :         console_driver->name_base = 1;
    3489                 :          3 :         console_driver->major = TTY_MAJOR;
    3490                 :          3 :         console_driver->minor_start = 1;
    3491                 :          3 :         console_driver->type = TTY_DRIVER_TYPE_CONSOLE;
    3492                 :          3 :         console_driver->init_termios = tty_std_termios;
    3493                 :          3 :         if (default_utf8)
    3494                 :          3 :                 console_driver->init_termios.c_iflag |= IUTF8;
    3495                 :          3 :         console_driver->flags = TTY_DRIVER_REAL_RAW | TTY_DRIVER_RESET_TERMIOS;
    3496                 :          3 :         tty_set_operations(console_driver, &con_ops);
    3497                 :          3 :         if (tty_register_driver(console_driver))
    3498                 :          0 :                 panic("Couldn't register console driver\n");
    3499                 :          3 :         kbd_init();
    3500                 :          3 :         console_map_init();
    3501                 :            : #ifdef CONFIG_MDA_CONSOLE
    3502                 :            :         mda_console_init();
    3503                 :            : #endif
    3504                 :          3 :         return 0;
    3505                 :            : }
    3506                 :            : 
    3507                 :            : #ifndef VT_SINGLE_DRIVER
    3508                 :            : 
    3509                 :            : static struct class *vtconsole_class;
    3510                 :            : 
    3511                 :          3 : static int do_bind_con_driver(const struct consw *csw, int first, int last,
    3512                 :            :                            int deflt)
    3513                 :            : {
    3514                 :          3 :         struct module *owner = csw->owner;
    3515                 :            :         const char *desc = NULL;
    3516                 :            :         struct con_driver *con_driver;
    3517                 :            :         int i, j = -1, k = -1, retval = -ENODEV;
    3518                 :            : 
    3519                 :          3 :         if (!try_module_get(owner))
    3520                 :            :                 return -ENODEV;
    3521                 :            : 
    3522                 :          3 :         WARN_CONSOLE_UNLOCKED();
    3523                 :            : 
    3524                 :            :         /* check if driver is registered */
    3525                 :          3 :         for (i = 0; i < MAX_NR_CON_DRIVER; i++) {
    3526                 :          3 :                 con_driver = &registered_con_driver[i];
    3527                 :            : 
    3528                 :          3 :                 if (con_driver->con == csw) {
    3529                 :          3 :                         desc = con_driver->desc;
    3530                 :            :                         retval = 0;
    3531                 :          3 :                         break;
    3532                 :            :                 }
    3533                 :            :         }
    3534                 :            : 
    3535                 :          3 :         if (retval)
    3536                 :            :                 goto err;
    3537                 :            : 
    3538                 :          3 :         if (!(con_driver->flag & CON_DRIVER_FLAG_INIT)) {
    3539                 :          0 :                 csw->con_startup();
    3540                 :          0 :                 con_driver->flag |= CON_DRIVER_FLAG_INIT;
    3541                 :            :         }
    3542                 :            : 
    3543                 :          3 :         if (deflt) {
    3544                 :          3 :                 if (conswitchp)
    3545                 :          3 :                         module_put(conswitchp->owner);
    3546                 :            : 
    3547                 :          3 :                 __module_get(owner);
    3548                 :          3 :                 conswitchp = csw;
    3549                 :            :         }
    3550                 :            : 
    3551                 :          3 :         first = max(first, con_driver->first);
    3552                 :          3 :         last = min(last, con_driver->last);
    3553                 :            : 
    3554                 :          3 :         for (i = first; i <= last; i++) {
    3555                 :            :                 int old_was_color;
    3556                 :          3 :                 struct vc_data *vc = vc_cons[i].d;
    3557                 :            : 
    3558                 :          3 :                 if (con_driver_map[i])
    3559                 :          3 :                         module_put(con_driver_map[i]->owner);
    3560                 :          3 :                 __module_get(owner);
    3561                 :          3 :                 con_driver_map[i] = csw;
    3562                 :            : 
    3563                 :          3 :                 if (!vc || !vc->vc_sw)
    3564                 :          3 :                         continue;
    3565                 :            : 
    3566                 :            :                 j = i;
    3567                 :            : 
    3568                 :          3 :                 if (con_is_visible(vc)) {
    3569                 :            :                         k = i;
    3570                 :          3 :                         save_screen(vc);
    3571                 :            :                 }
    3572                 :            : 
    3573                 :          3 :                 old_was_color = vc->vc_can_do_color;
    3574                 :          3 :                 vc->vc_sw->con_deinit(vc);
    3575                 :          3 :                 vc->vc_origin = (unsigned long)vc->vc_screenbuf;
    3576                 :          3 :                 visual_init(vc, i, 0);
    3577                 :          3 :                 set_origin(vc);
    3578                 :          3 :                 update_attr(vc);
    3579                 :            : 
    3580                 :            :                 /* If the console changed between mono <-> color, then
    3581                 :            :                  * the attributes in the screenbuf will be wrong.  The
    3582                 :            :                  * following resets all attributes to something sane.
    3583                 :            :                  */
    3584                 :          3 :                 if (old_was_color != vc->vc_can_do_color)
    3585                 :          0 :                         clear_buffer_attributes(vc);
    3586                 :            :         }
    3587                 :            : 
    3588                 :          3 :         pr_info("Console: switching ");
    3589                 :          3 :         if (!deflt)
    3590                 :          0 :                 pr_cont("consoles %d-%d ", first + 1, last + 1);
    3591                 :          3 :         if (j >= 0) {
    3592                 :          3 :                 struct vc_data *vc = vc_cons[j].d;
    3593                 :            : 
    3594                 :          3 :                 pr_cont("to %s %s %dx%d\n",
    3595                 :            :                         vc->vc_can_do_color ? "colour" : "mono",
    3596                 :            :                         desc, vc->vc_cols, vc->vc_rows);
    3597                 :            : 
    3598                 :          3 :                 if (k >= 0) {
    3599                 :          3 :                         vc = vc_cons[k].d;
    3600                 :          3 :                         update_screen(vc);
    3601                 :            :                 }
    3602                 :            :         } else {
    3603                 :          0 :                 pr_cont("to %s\n", desc);
    3604                 :            :         }
    3605                 :            : 
    3606                 :            :         retval = 0;
    3607                 :            : err:
    3608                 :          3 :         module_put(owner);
    3609                 :          3 :         return retval;
    3610                 :            : };
    3611                 :            : 
    3612                 :            : 
    3613                 :            : #ifdef CONFIG_VT_HW_CONSOLE_BINDING
    3614                 :            : /* unlocked version of unbind_con_driver() */
    3615                 :          0 : int do_unbind_con_driver(const struct consw *csw, int first, int last, int deflt)
    3616                 :            : {
    3617                 :          0 :         struct module *owner = csw->owner;
    3618                 :            :         const struct consw *defcsw = NULL;
    3619                 :            :         struct con_driver *con_driver = NULL, *con_back = NULL;
    3620                 :            :         int i, retval = -ENODEV;
    3621                 :            : 
    3622                 :          0 :         if (!try_module_get(owner))
    3623                 :            :                 return -ENODEV;
    3624                 :            : 
    3625                 :          0 :         WARN_CONSOLE_UNLOCKED();
    3626                 :            : 
    3627                 :            :         /* check if driver is registered and if it is unbindable */
    3628                 :          0 :         for (i = 0; i < MAX_NR_CON_DRIVER; i++) {
    3629                 :          0 :                 con_driver = &registered_con_driver[i];
    3630                 :            : 
    3631                 :          0 :                 if (con_driver->con == csw &&
    3632                 :          0 :                     con_driver->flag & CON_DRIVER_FLAG_MODULE) {
    3633                 :            :                         retval = 0;
    3634                 :            :                         break;
    3635                 :            :                 }
    3636                 :            :         }
    3637                 :            : 
    3638                 :          0 :         if (retval)
    3639                 :            :                 goto err;
    3640                 :            : 
    3641                 :            :         retval = -ENODEV;
    3642                 :            : 
    3643                 :            :         /* check if backup driver exists */
    3644                 :          0 :         for (i = 0; i < MAX_NR_CON_DRIVER; i++) {
    3645                 :          0 :                 con_back = &registered_con_driver[i];
    3646                 :            : 
    3647                 :          0 :                 if (con_back->con && con_back->con != csw) {
    3648                 :          0 :                         defcsw = con_back->con;
    3649                 :            :                         retval = 0;
    3650                 :          0 :                         break;
    3651                 :            :                 }
    3652                 :            :         }
    3653                 :            : 
    3654                 :          0 :         if (retval)
    3655                 :            :                 goto err;
    3656                 :            : 
    3657                 :          0 :         if (!con_is_bound(csw))
    3658                 :            :                 goto err;
    3659                 :            : 
    3660                 :          0 :         first = max(first, con_driver->first);
    3661                 :          0 :         last = min(last, con_driver->last);
    3662                 :            : 
    3663                 :          0 :         for (i = first; i <= last; i++) {
    3664                 :          0 :                 if (con_driver_map[i] == csw) {
    3665                 :          0 :                         module_put(csw->owner);
    3666                 :          0 :                         con_driver_map[i] = NULL;
    3667                 :            :                 }
    3668                 :            :         }
    3669                 :            : 
    3670                 :          0 :         if (!con_is_bound(defcsw)) {
    3671                 :          0 :                 const struct consw *defconsw = conswitchp;
    3672                 :            : 
    3673                 :          0 :                 defcsw->con_startup();
    3674                 :          0 :                 con_back->flag |= CON_DRIVER_FLAG_INIT;
    3675                 :            :                 /*
    3676                 :            :                  * vgacon may change the default driver to point
    3677                 :            :                  * to dummycon, we restore it here...
    3678                 :            :                  */
    3679                 :          0 :                 conswitchp = defconsw;
    3680                 :            :         }
    3681                 :            : 
    3682                 :          0 :         if (!con_is_bound(csw))
    3683                 :          0 :                 con_driver->flag &= ~CON_DRIVER_FLAG_INIT;
    3684                 :            : 
    3685                 :            :         /* ignore return value, binding should not fail */
    3686                 :          0 :         do_bind_con_driver(defcsw, first, last, deflt);
    3687                 :            : err:
    3688                 :          0 :         module_put(owner);
    3689                 :          0 :         return retval;
    3690                 :            : 
    3691                 :            : }
    3692                 :            : EXPORT_SYMBOL_GPL(do_unbind_con_driver);
    3693                 :            : 
    3694                 :          0 : static int vt_bind(struct con_driver *con)
    3695                 :            : {
    3696                 :            :         const struct consw *defcsw = NULL, *csw = NULL;
    3697                 :            :         int i, more = 1, first = -1, last = -1, deflt = 0;
    3698                 :            : 
    3699                 :          0 :         if (!con->con || !(con->flag & CON_DRIVER_FLAG_MODULE))
    3700                 :            :                 goto err;
    3701                 :            : 
    3702                 :            :         csw = con->con;
    3703                 :            : 
    3704                 :          0 :         for (i = 0; i < MAX_NR_CON_DRIVER; i++) {
    3705                 :            :                 struct con_driver *con = &registered_con_driver[i];
    3706                 :            : 
    3707                 :          0 :                 if (con->con && !(con->flag & CON_DRIVER_FLAG_MODULE)) {
    3708                 :          0 :                         defcsw = con->con;
    3709                 :          0 :                         break;
    3710                 :            :                 }
    3711                 :            :         }
    3712                 :            : 
    3713                 :          0 :         if (!defcsw)
    3714                 :            :                 goto err;
    3715                 :            : 
    3716                 :          0 :         while (more) {
    3717                 :            :                 more = 0;
    3718                 :            : 
    3719                 :          0 :                 for (i = con->first; i <= con->last; i++) {
    3720                 :          0 :                         if (con_driver_map[i] == defcsw) {
    3721                 :          0 :                                 if (first == -1)
    3722                 :            :                                         first = i;
    3723                 :            :                                 last = i;
    3724                 :            :                                 more = 1;
    3725                 :          0 :                         } else if (first != -1)
    3726                 :            :                                 break;
    3727                 :            :                 }
    3728                 :            : 
    3729                 :          0 :                 if (first == 0 && last == MAX_NR_CONSOLES -1)
    3730                 :            :                         deflt = 1;
    3731                 :            : 
    3732                 :          0 :                 if (first != -1)
    3733                 :          0 :                         do_bind_con_driver(csw, first, last, deflt);
    3734                 :            : 
    3735                 :            :                 first = -1;
    3736                 :            :                 last = -1;
    3737                 :            :                 deflt = 0;
    3738                 :            :         }
    3739                 :            : 
    3740                 :            : err:
    3741                 :          0 :         return 0;
    3742                 :            : }
    3743                 :            : 
    3744                 :          0 : static int vt_unbind(struct con_driver *con)
    3745                 :            : {
    3746                 :            :         const struct consw *csw = NULL;
    3747                 :            :         int i, more = 1, first = -1, last = -1, deflt = 0;
    3748                 :            :         int ret;
    3749                 :            : 
    3750                 :          0 :         if (!con->con || !(con->flag & CON_DRIVER_FLAG_MODULE))
    3751                 :            :                 goto err;
    3752                 :            : 
    3753                 :            :         csw = con->con;
    3754                 :            : 
    3755                 :          0 :         while (more) {
    3756                 :            :                 more = 0;
    3757                 :            : 
    3758                 :          0 :                 for (i = con->first; i <= con->last; i++) {
    3759                 :          0 :                         if (con_driver_map[i] == csw) {
    3760                 :          0 :                                 if (first == -1)
    3761                 :            :                                         first = i;
    3762                 :            :                                 last = i;
    3763                 :            :                                 more = 1;
    3764                 :          0 :                         } else if (first != -1)
    3765                 :            :                                 break;
    3766                 :            :                 }
    3767                 :            : 
    3768                 :          0 :                 if (first == 0 && last == MAX_NR_CONSOLES -1)
    3769                 :            :                         deflt = 1;
    3770                 :            : 
    3771                 :          0 :                 if (first != -1) {
    3772                 :          0 :                         ret = do_unbind_con_driver(csw, first, last, deflt);
    3773                 :          0 :                         if (ret != 0)
    3774                 :          0 :                                 return ret;
    3775                 :            :                 }
    3776                 :            : 
    3777                 :            :                 first = -1;
    3778                 :            :                 last = -1;
    3779                 :            :                 deflt = 0;
    3780                 :            :         }
    3781                 :            : 
    3782                 :            : err:
    3783                 :            :         return 0;
    3784                 :            : }
    3785                 :            : #else
    3786                 :            : static inline int vt_bind(struct con_driver *con)
    3787                 :            : {
    3788                 :            :         return 0;
    3789                 :            : }
    3790                 :            : static inline int vt_unbind(struct con_driver *con)
    3791                 :            : {
    3792                 :            :         return 0;
    3793                 :            : }
    3794                 :            : #endif /* CONFIG_VT_HW_CONSOLE_BINDING */
    3795                 :            : 
    3796                 :          0 : static ssize_t store_bind(struct device *dev, struct device_attribute *attr,
    3797                 :            :                           const char *buf, size_t count)
    3798                 :            : {
    3799                 :            :         struct con_driver *con = dev_get_drvdata(dev);
    3800                 :          0 :         int bind = simple_strtoul(buf, NULL, 0);
    3801                 :            : 
    3802                 :          0 :         console_lock();
    3803                 :            : 
    3804                 :          0 :         if (bind)
    3805                 :          0 :                 vt_bind(con);
    3806                 :            :         else
    3807                 :          0 :                 vt_unbind(con);
    3808                 :            : 
    3809                 :          0 :         console_unlock();
    3810                 :            : 
    3811                 :          0 :         return count;
    3812                 :            : }
    3813                 :            : 
    3814                 :          0 : static ssize_t show_bind(struct device *dev, struct device_attribute *attr,
    3815                 :            :                          char *buf)
    3816                 :            : {
    3817                 :            :         struct con_driver *con = dev_get_drvdata(dev);
    3818                 :            :         int bind;
    3819                 :            : 
    3820                 :          0 :         console_lock();
    3821                 :          0 :         bind = con_is_bound(con->con);
    3822                 :          0 :         console_unlock();
    3823                 :            : 
    3824                 :          0 :         return snprintf(buf, PAGE_SIZE, "%i\n", bind);
    3825                 :            : }
    3826                 :            : 
    3827                 :          0 : static ssize_t show_name(struct device *dev, struct device_attribute *attr,
    3828                 :            :                          char *buf)
    3829                 :            : {
    3830                 :            :         struct con_driver *con = dev_get_drvdata(dev);
    3831                 :            : 
    3832                 :          0 :         return snprintf(buf, PAGE_SIZE, "%s %s\n",
    3833                 :          0 :                         (con->flag & CON_DRIVER_FLAG_MODULE) ? "(M)" : "(S)",
    3834                 :            :                          con->desc);
    3835                 :            : 
    3836                 :            : }
    3837                 :            : 
    3838                 :            : static DEVICE_ATTR(bind, S_IRUGO|S_IWUSR, show_bind, store_bind);
    3839                 :            : static DEVICE_ATTR(name, S_IRUGO, show_name, NULL);
    3840                 :            : 
    3841                 :            : static struct attribute *con_dev_attrs[] = {
    3842                 :            :         &dev_attr_bind.attr,
    3843                 :            :         &dev_attr_name.attr,
    3844                 :            :         NULL
    3845                 :            : };
    3846                 :            : 
    3847                 :            : ATTRIBUTE_GROUPS(con_dev);
    3848                 :            : 
    3849                 :            : static int vtconsole_init_device(struct con_driver *con)
    3850                 :            : {
    3851                 :          3 :         con->flag |= CON_DRIVER_FLAG_ATTR;
    3852                 :            :         return 0;
    3853                 :            : }
    3854                 :            : 
    3855                 :            : static void vtconsole_deinit_device(struct con_driver *con)
    3856                 :            : {
    3857                 :          0 :         con->flag &= ~CON_DRIVER_FLAG_ATTR;
    3858                 :            : }
    3859                 :            : 
    3860                 :            : /**
    3861                 :            :  * con_is_bound - checks if driver is bound to the console
    3862                 :            :  * @csw: console driver
    3863                 :            :  *
    3864                 :            :  * RETURNS: zero if unbound, nonzero if bound
    3865                 :            :  *
    3866                 :            :  * Drivers can call this and if zero, they should release
    3867                 :            :  * all resources allocated on con_startup()
    3868                 :            :  */
    3869                 :          0 : int con_is_bound(const struct consw *csw)
    3870                 :            : {
    3871                 :            :         int i, bound = 0;
    3872                 :            : 
    3873                 :          0 :         WARN_CONSOLE_UNLOCKED();
    3874                 :            : 
    3875                 :          0 :         for (i = 0; i < MAX_NR_CONSOLES; i++) {
    3876                 :          0 :                 if (con_driver_map[i] == csw) {
    3877                 :            :                         bound = 1;
    3878                 :            :                         break;
    3879                 :            :                 }
    3880                 :            :         }
    3881                 :            : 
    3882                 :          0 :         return bound;
    3883                 :            : }
    3884                 :            : EXPORT_SYMBOL(con_is_bound);
    3885                 :            : 
    3886                 :            : /**
    3887                 :            :  * con_is_visible - checks whether the current console is visible
    3888                 :            :  * @vc: virtual console
    3889                 :            :  *
    3890                 :            :  * RETURNS: zero if not visible, nonzero if visible
    3891                 :            :  */
    3892                 :          3 : bool con_is_visible(const struct vc_data *vc)
    3893                 :            : {
    3894                 :          3 :         WARN_CONSOLE_UNLOCKED();
    3895                 :            : 
    3896                 :          3 :         return *vc->vc_display_fg == vc;
    3897                 :            : }
    3898                 :            : EXPORT_SYMBOL(con_is_visible);
    3899                 :            : 
    3900                 :            : /**
    3901                 :            :  * con_debug_enter - prepare the console for the kernel debugger
    3902                 :            :  * @sw: console driver
    3903                 :            :  *
    3904                 :            :  * Called when the console is taken over by the kernel debugger, this
    3905                 :            :  * function needs to save the current console state, then put the console
    3906                 :            :  * into a state suitable for the kernel debugger.
    3907                 :            :  *
    3908                 :            :  * RETURNS:
    3909                 :            :  * Zero on success, nonzero if a failure occurred when trying to prepare
    3910                 :            :  * the console for the debugger.
    3911                 :            :  */
    3912                 :          0 : int con_debug_enter(struct vc_data *vc)
    3913                 :            : {
    3914                 :            :         int ret = 0;
    3915                 :            : 
    3916                 :          0 :         saved_fg_console = fg_console;
    3917                 :          0 :         saved_last_console = last_console;
    3918                 :          0 :         saved_want_console = want_console;
    3919                 :          0 :         saved_vc_mode = vc->vc_mode;
    3920                 :          0 :         saved_console_blanked = console_blanked;
    3921                 :          0 :         vc->vc_mode = KD_TEXT;
    3922                 :          0 :         console_blanked = 0;
    3923                 :          0 :         if (vc->vc_sw->con_debug_enter)
    3924                 :          0 :                 ret = vc->vc_sw->con_debug_enter(vc);
    3925                 :            : #ifdef CONFIG_KGDB_KDB
    3926                 :            :         /* Set the initial LINES variable if it is not already set */
    3927                 :          0 :         if (vc->vc_rows < 999) {
    3928                 :            :                 int linecount;
    3929                 :            :                 char lns[4];
    3930                 :          0 :                 const char *setargs[3] = {
    3931                 :            :                         "set",
    3932                 :            :                         "LINES",
    3933                 :            :                         lns,
    3934                 :            :                 };
    3935                 :          0 :                 if (kdbgetintenv(setargs[0], &linecount)) {
    3936                 :          0 :                         snprintf(lns, 4, "%i", vc->vc_rows);
    3937                 :          0 :                         kdb_set(2, setargs);
    3938                 :            :                 }
    3939                 :            :         }
    3940                 :          0 :         if (vc->vc_cols < 999) {
    3941                 :            :                 int colcount;
    3942                 :            :                 char cols[4];
    3943                 :          0 :                 const char *setargs[3] = {
    3944                 :            :                         "set",
    3945                 :            :                         "COLUMNS",
    3946                 :            :                         cols,
    3947                 :            :                 };
    3948                 :          0 :                 if (kdbgetintenv(setargs[0], &colcount)) {
    3949                 :          0 :                         snprintf(cols, 4, "%i", vc->vc_cols);
    3950                 :          0 :                         kdb_set(2, setargs);
    3951                 :            :                 }
    3952                 :            :         }
    3953                 :            : #endif /* CONFIG_KGDB_KDB */
    3954                 :          0 :         return ret;
    3955                 :            : }
    3956                 :            : EXPORT_SYMBOL_GPL(con_debug_enter);
    3957                 :            : 
    3958                 :            : /**
    3959                 :            :  * con_debug_leave - restore console state
    3960                 :            :  * @sw: console driver
    3961                 :            :  *
    3962                 :            :  * Restore the console state to what it was before the kernel debugger
    3963                 :            :  * was invoked.
    3964                 :            :  *
    3965                 :            :  * RETURNS:
    3966                 :            :  * Zero on success, nonzero if a failure occurred when trying to restore
    3967                 :            :  * the console.
    3968                 :            :  */
    3969                 :          0 : int con_debug_leave(void)
    3970                 :            : {
    3971                 :            :         struct vc_data *vc;
    3972                 :            :         int ret = 0;
    3973                 :            : 
    3974                 :          0 :         fg_console = saved_fg_console;
    3975                 :          0 :         last_console = saved_last_console;
    3976                 :          0 :         want_console = saved_want_console;
    3977                 :          0 :         console_blanked = saved_console_blanked;
    3978                 :          0 :         vc_cons[fg_console].d->vc_mode = saved_vc_mode;
    3979                 :            : 
    3980                 :          0 :         vc = vc_cons[fg_console].d;
    3981                 :          0 :         if (vc->vc_sw->con_debug_leave)
    3982                 :          0 :                 ret = vc->vc_sw->con_debug_leave(vc);
    3983                 :          0 :         return ret;
    3984                 :            : }
    3985                 :            : EXPORT_SYMBOL_GPL(con_debug_leave);
    3986                 :            : 
    3987                 :          3 : static int do_register_con_driver(const struct consw *csw, int first, int last)
    3988                 :            : {
    3989                 :          3 :         struct module *owner = csw->owner;
    3990                 :            :         struct con_driver *con_driver;
    3991                 :            :         const char *desc;
    3992                 :            :         int i, retval;
    3993                 :            : 
    3994                 :          3 :         WARN_CONSOLE_UNLOCKED();
    3995                 :            : 
    3996                 :          3 :         if (!try_module_get(owner))
    3997                 :            :                 return -ENODEV;
    3998                 :            : 
    3999                 :          3 :         for (i = 0; i < MAX_NR_CON_DRIVER; i++) {
    4000                 :          3 :                 con_driver = &registered_con_driver[i];
    4001                 :            : 
    4002                 :            :                 /* already registered */
    4003                 :          3 :                 if (con_driver->con == csw) {
    4004                 :            :                         retval = -EBUSY;
    4005                 :            :                         goto err;
    4006                 :            :                 }
    4007                 :            :         }
    4008                 :            : 
    4009                 :          3 :         desc = csw->con_startup();
    4010                 :          3 :         if (!desc) {
    4011                 :            :                 retval = -ENODEV;
    4012                 :            :                 goto err;
    4013                 :            :         }
    4014                 :            : 
    4015                 :            :         retval = -EINVAL;
    4016                 :            : 
    4017                 :          3 :         for (i = 0; i < MAX_NR_CON_DRIVER; i++) {
    4018                 :          3 :                 con_driver = &registered_con_driver[i];
    4019                 :            : 
    4020                 :          3 :                 if (con_driver->con == NULL &&
    4021                 :          3 :                     !(con_driver->flag & CON_DRIVER_FLAG_ZOMBIE)) {
    4022                 :          3 :                         con_driver->con = csw;
    4023                 :          3 :                         con_driver->desc = desc;
    4024                 :          3 :                         con_driver->node = i;
    4025                 :          3 :                         con_driver->flag = CON_DRIVER_FLAG_MODULE |
    4026                 :            :                                            CON_DRIVER_FLAG_INIT;
    4027                 :          3 :                         con_driver->first = first;
    4028                 :          3 :                         con_driver->last = last;
    4029                 :            :                         retval = 0;
    4030                 :          3 :                         break;
    4031                 :            :                 }
    4032                 :            :         }
    4033                 :            : 
    4034                 :          3 :         if (retval)
    4035                 :            :                 goto err;
    4036                 :            : 
    4037                 :          3 :         con_driver->dev =
    4038                 :          3 :                 device_create_with_groups(vtconsole_class, NULL,
    4039                 :          3 :                                           MKDEV(0, con_driver->node),
    4040                 :            :                                           con_driver, con_dev_groups,
    4041                 :            :                                           "vtcon%i", con_driver->node);
    4042                 :          3 :         if (IS_ERR(con_driver->dev)) {
    4043                 :          0 :                 pr_warn("Unable to create device for %s; errno = %ld\n",
    4044                 :            :                         con_driver->desc, PTR_ERR(con_driver->dev));
    4045                 :          0 :                 con_driver->dev = NULL;
    4046                 :            :         } else {
    4047                 :            :                 vtconsole_init_device(con_driver);
    4048                 :            :         }
    4049                 :            : 
    4050                 :            : err:
    4051                 :          3 :         module_put(owner);
    4052                 :          3 :         return retval;
    4053                 :            : }
    4054                 :            : 
    4055                 :            : 
    4056                 :            : /**
    4057                 :            :  * do_unregister_con_driver - unregister console driver from console layer
    4058                 :            :  * @csw: console driver
    4059                 :            :  *
    4060                 :            :  * DESCRIPTION: All drivers that registers to the console layer must
    4061                 :            :  * call this function upon exit, or if the console driver is in a state
    4062                 :            :  * where it won't be able to handle console services, such as the
    4063                 :            :  * framebuffer console without loaded framebuffer drivers.
    4064                 :            :  *
    4065                 :            :  * The driver must unbind first prior to unregistration.
    4066                 :            :  */
    4067                 :          0 : int do_unregister_con_driver(const struct consw *csw)
    4068                 :            : {
    4069                 :            :         int i;
    4070                 :            : 
    4071                 :            :         /* cannot unregister a bound driver */
    4072                 :          0 :         if (con_is_bound(csw))
    4073                 :            :                 return -EBUSY;
    4074                 :            : 
    4075                 :          0 :         if (csw == conswitchp)
    4076                 :            :                 return -EINVAL;
    4077                 :            : 
    4078                 :          0 :         for (i = 0; i < MAX_NR_CON_DRIVER; i++) {
    4079                 :            :                 struct con_driver *con_driver = &registered_con_driver[i];
    4080                 :            : 
    4081                 :          0 :                 if (con_driver->con == csw) {
    4082                 :            :                         /*
    4083                 :            :                          * Defer the removal of the sysfs entries since that
    4084                 :            :                          * will acquire the kernfs s_active lock and we can't
    4085                 :            :                          * acquire this lock while holding the console lock:
    4086                 :            :                          * the unbind sysfs entry imposes already the opposite
    4087                 :            :                          * order. Reset con already here to prevent any later
    4088                 :            :                          * lookup to succeed and mark this slot as zombie, so
    4089                 :            :                          * it won't get reused until we complete the removal
    4090                 :            :                          * in the deferred work.
    4091                 :            :                          */
    4092                 :          0 :                         con_driver->con = NULL;
    4093                 :          0 :                         con_driver->flag = CON_DRIVER_FLAG_ZOMBIE;
    4094                 :            :                         schedule_work(&con_driver_unregister_work);
    4095                 :            : 
    4096                 :          0 :                         return 0;
    4097                 :            :                 }
    4098                 :            :         }
    4099                 :            : 
    4100                 :            :         return -ENODEV;
    4101                 :            : }
    4102                 :            : EXPORT_SYMBOL_GPL(do_unregister_con_driver);
    4103                 :            : 
    4104                 :          0 : static void con_driver_unregister_callback(struct work_struct *ignored)
    4105                 :            : {
    4106                 :            :         int i;
    4107                 :            : 
    4108                 :          0 :         console_lock();
    4109                 :            : 
    4110                 :          0 :         for (i = 0; i < MAX_NR_CON_DRIVER; i++) {
    4111                 :            :                 struct con_driver *con_driver = &registered_con_driver[i];
    4112                 :            : 
    4113                 :          0 :                 if (!(con_driver->flag & CON_DRIVER_FLAG_ZOMBIE))
    4114                 :          0 :                         continue;
    4115                 :            : 
    4116                 :          0 :                 console_unlock();
    4117                 :            : 
    4118                 :            :                 vtconsole_deinit_device(con_driver);
    4119                 :          0 :                 device_destroy(vtconsole_class, MKDEV(0, con_driver->node));
    4120                 :            : 
    4121                 :          0 :                 console_lock();
    4122                 :            : 
    4123                 :          0 :                 if (WARN_ON_ONCE(con_driver->con))
    4124                 :          0 :                         con_driver->con = NULL;
    4125                 :          0 :                 con_driver->desc = NULL;
    4126                 :          0 :                 con_driver->dev = NULL;
    4127                 :          0 :                 con_driver->node = 0;
    4128                 :          0 :                 WARN_ON_ONCE(con_driver->flag != CON_DRIVER_FLAG_ZOMBIE);
    4129                 :          0 :                 con_driver->flag = 0;
    4130                 :          0 :                 con_driver->first = 0;
    4131                 :          0 :                 con_driver->last = 0;
    4132                 :            :         }
    4133                 :            : 
    4134                 :          0 :         console_unlock();
    4135                 :          0 : }
    4136                 :            : 
    4137                 :            : /*
    4138                 :            :  *      If we support more console drivers, this function is used
    4139                 :            :  *      when a driver wants to take over some existing consoles
    4140                 :            :  *      and become default driver for newly opened ones.
    4141                 :            :  *
    4142                 :            :  *      do_take_over_console is basically a register followed by unbind
    4143                 :            :  */
    4144                 :          3 : int do_take_over_console(const struct consw *csw, int first, int last, int deflt)
    4145                 :            : {
    4146                 :            :         int err;
    4147                 :            : 
    4148                 :          3 :         err = do_register_con_driver(csw, first, last);
    4149                 :            :         /*
    4150                 :            :          * If we get an busy error we still want to bind the console driver
    4151                 :            :          * and return success, as we may have unbound the console driver
    4152                 :            :          * but not unregistered it.
    4153                 :            :          */
    4154                 :          3 :         if (err == -EBUSY)
    4155                 :            :                 err = 0;
    4156                 :          3 :         if (!err)
    4157                 :          3 :                 do_bind_con_driver(csw, first, last, deflt);
    4158                 :            : 
    4159                 :          3 :         return err;
    4160                 :            : }
    4161                 :            : EXPORT_SYMBOL_GPL(do_take_over_console);
    4162                 :            : 
    4163                 :            : 
    4164                 :            : /*
    4165                 :            :  * give_up_console is a wrapper to unregister_con_driver. It will only
    4166                 :            :  * work if driver is fully unbound.
    4167                 :            :  */
    4168                 :          0 : void give_up_console(const struct consw *csw)
    4169                 :            : {
    4170                 :          0 :         console_lock();
    4171                 :          0 :         do_unregister_con_driver(csw);
    4172                 :          0 :         console_unlock();
    4173                 :          0 : }
    4174                 :            : 
    4175                 :          3 : static int __init vtconsole_class_init(void)
    4176                 :            : {
    4177                 :            :         int i;
    4178                 :            : 
    4179                 :          3 :         vtconsole_class = class_create(THIS_MODULE, "vtconsole");
    4180                 :          3 :         if (IS_ERR(vtconsole_class)) {
    4181                 :          0 :                 pr_warn("Unable to create vt console class; errno = %ld\n",
    4182                 :            :                         PTR_ERR(vtconsole_class));
    4183                 :          0 :                 vtconsole_class = NULL;
    4184                 :            :         }
    4185                 :            : 
    4186                 :            :         /* Add system drivers to sysfs */
    4187                 :          3 :         for (i = 0; i < MAX_NR_CON_DRIVER; i++) {
    4188                 :          3 :                 struct con_driver *con = &registered_con_driver[i];
    4189                 :            : 
    4190                 :          3 :                 if (con->con && !con->dev) {
    4191                 :          3 :                         con->dev =
    4192                 :          3 :                                 device_create_with_groups(vtconsole_class, NULL,
    4193                 :          3 :                                                           MKDEV(0, con->node),
    4194                 :            :                                                           con, con_dev_groups,
    4195                 :            :                                                           "vtcon%i", con->node);
    4196                 :            : 
    4197                 :          3 :                         if (IS_ERR(con->dev)) {
    4198                 :          0 :                                 pr_warn("Unable to create device for %s; errno = %ld\n",
    4199                 :            :                                         con->desc, PTR_ERR(con->dev));
    4200                 :          0 :                                 con->dev = NULL;
    4201                 :            :                         } else {
    4202                 :            :                                 vtconsole_init_device(con);
    4203                 :            :                         }
    4204                 :            :                 }
    4205                 :            :         }
    4206                 :            : 
    4207                 :          3 :         return 0;
    4208                 :            : }
    4209                 :            : postcore_initcall(vtconsole_class_init);
    4210                 :            : 
    4211                 :            : #endif
    4212                 :            : 
    4213                 :            : /*
    4214                 :            :  *      Screen blanking
    4215                 :            :  */
    4216                 :            : 
    4217                 :          0 : static int set_vesa_blanking(char __user *p)
    4218                 :            : {
    4219                 :            :         unsigned int mode;
    4220                 :            : 
    4221                 :          0 :         if (get_user(mode, p + 1))
    4222                 :            :                 return -EFAULT;
    4223                 :            : 
    4224                 :          0 :         vesa_blank_mode = (mode < 4) ? mode : 0;
    4225                 :          0 :         return 0;
    4226                 :            : }
    4227                 :            : 
    4228                 :          3 : void do_blank_screen(int entering_gfx)
    4229                 :            : {
    4230                 :          3 :         struct vc_data *vc = vc_cons[fg_console].d;
    4231                 :            :         int i;
    4232                 :            : 
    4233                 :          3 :         might_sleep();
    4234                 :            : 
    4235                 :          3 :         WARN_CONSOLE_UNLOCKED();
    4236                 :            : 
    4237                 :          3 :         if (console_blanked) {
    4238                 :          0 :                 if (blank_state == blank_vesa_wait) {
    4239                 :          0 :                         blank_state = blank_off;
    4240                 :          0 :                         vc->vc_sw->con_blank(vc, vesa_blank_mode + 1, 0);
    4241                 :            :                 }
    4242                 :            :                 return;
    4243                 :            :         }
    4244                 :            : 
    4245                 :            :         /* entering graphics mode? */
    4246                 :          3 :         if (entering_gfx) {
    4247                 :          3 :                 hide_cursor(vc);
    4248                 :          3 :                 save_screen(vc);
    4249                 :          3 :                 vc->vc_sw->con_blank(vc, -1, 1);
    4250                 :          3 :                 console_blanked = fg_console + 1;
    4251                 :          3 :                 blank_state = blank_off;
    4252                 :          3 :                 set_origin(vc);
    4253                 :          3 :                 return;
    4254                 :            :         }
    4255                 :            : 
    4256                 :          0 :         blank_state = blank_off;
    4257                 :            : 
    4258                 :            :         /* don't blank graphics */
    4259                 :          0 :         if (vc->vc_mode != KD_TEXT) {
    4260                 :          0 :                 console_blanked = fg_console + 1;
    4261                 :          0 :                 return;
    4262                 :            :         }
    4263                 :            : 
    4264                 :          0 :         hide_cursor(vc);
    4265                 :          0 :         del_timer_sync(&console_timer);
    4266                 :          0 :         blank_timer_expired = 0;
    4267                 :            : 
    4268                 :          0 :         save_screen(vc);
    4269                 :            :         /* In case we need to reset origin, blanking hook returns 1 */
    4270                 :          0 :         i = vc->vc_sw->con_blank(vc, vesa_off_interval ? 1 : (vesa_blank_mode + 1), 0);
    4271                 :          0 :         console_blanked = fg_console + 1;
    4272                 :          0 :         if (i)
    4273                 :          0 :                 set_origin(vc);
    4274                 :            : 
    4275                 :          0 :         if (console_blank_hook && console_blank_hook(1))
    4276                 :            :                 return;
    4277                 :            : 
    4278                 :          0 :         if (vesa_off_interval && vesa_blank_mode) {
    4279                 :          0 :                 blank_state = blank_vesa_wait;
    4280                 :          0 :                 mod_timer(&console_timer, jiffies + vesa_off_interval);
    4281                 :            :         }
    4282                 :          0 :         vt_event_post(VT_EVENT_BLANK, vc->vc_num, vc->vc_num);
    4283                 :            : }
    4284                 :            : EXPORT_SYMBOL(do_blank_screen);
    4285                 :            : 
    4286                 :            : /*
    4287                 :            :  * Called by timer as well as from vt_console_driver
    4288                 :            :  */
    4289                 :          2 : void do_unblank_screen(int leaving_gfx)
    4290                 :            : {
    4291                 :            :         struct vc_data *vc;
    4292                 :            : 
    4293                 :            :         /* This should now always be called from a "sane" (read: can schedule)
    4294                 :            :          * context for the sake of the low level drivers, except in the special
    4295                 :            :          * case of oops_in_progress
    4296                 :            :          */
    4297                 :          2 :         if (!oops_in_progress)
    4298                 :          2 :                 might_sleep();
    4299                 :            : 
    4300                 :          2 :         WARN_CONSOLE_UNLOCKED();
    4301                 :            : 
    4302                 :          2 :         ignore_poke = 0;
    4303                 :          2 :         if (!console_blanked)
    4304                 :            :                 return;
    4305                 :          2 :         if (!vc_cons_allocated(fg_console)) {
    4306                 :            :                 /* impossible */
    4307                 :          0 :                 pr_warn("unblank_screen: tty %d not allocated ??\n",
    4308                 :            :                         fg_console + 1);
    4309                 :          0 :                 return;
    4310                 :            :         }
    4311                 :          2 :         vc = vc_cons[fg_console].d;
    4312                 :          2 :         if (vc->vc_mode != KD_TEXT)
    4313                 :            :                 return; /* but leave console_blanked != 0 */
    4314                 :            : 
    4315                 :          2 :         if (blankinterval) {
    4316                 :          0 :                 mod_timer(&console_timer, jiffies + (blankinterval * HZ));
    4317                 :          0 :                 blank_state = blank_normal_wait;
    4318                 :            :         }
    4319                 :            : 
    4320                 :          2 :         console_blanked = 0;
    4321                 :          2 :         if (vc->vc_sw->con_blank(vc, 0, leaving_gfx))
    4322                 :            :                 /* Low-level driver cannot restore -> do it ourselves */
    4323                 :          0 :                 update_screen(vc);
    4324                 :          2 :         if (console_blank_hook)
    4325                 :          0 :                 console_blank_hook(0);
    4326                 :          2 :         set_palette(vc);
    4327                 :          2 :         set_cursor(vc);
    4328                 :          2 :         vt_event_post(VT_EVENT_UNBLANK, vc->vc_num, vc->vc_num);
    4329                 :            : }
    4330                 :            : EXPORT_SYMBOL(do_unblank_screen);
    4331                 :            : 
    4332                 :            : /*
    4333                 :            :  * This is called by the outside world to cause a forced unblank, mostly for
    4334                 :            :  * oopses. Currently, I just call do_unblank_screen(0), but we could eventually
    4335                 :            :  * call it with 1 as an argument and so force a mode restore... that may kill
    4336                 :            :  * X or at least garbage the screen but would also make the Oops visible...
    4337                 :            :  */
    4338                 :          0 : void unblank_screen(void)
    4339                 :            : {
    4340                 :          0 :         do_unblank_screen(0);
    4341                 :          0 : }
    4342                 :            : 
    4343                 :            : /*
    4344                 :            :  * We defer the timer blanking to work queue so it can take the console mutex
    4345                 :            :  * (console operations can still happen at irq time, but only from printk which
    4346                 :            :  * has the console mutex. Not perfect yet, but better than no locking
    4347                 :            :  */
    4348                 :          0 : static void blank_screen_t(struct timer_list *unused)
    4349                 :            : {
    4350                 :          0 :         blank_timer_expired = 1;
    4351                 :            :         schedule_work(&console_work);
    4352                 :          0 : }
    4353                 :            : 
    4354                 :          3 : void poke_blanked_console(void)
    4355                 :            : {
    4356                 :          3 :         WARN_CONSOLE_UNLOCKED();
    4357                 :            : 
    4358                 :            :         /* Add this so we quickly catch whoever might call us in a non
    4359                 :            :          * safe context. Nowadays, unblank_screen() isn't to be called in
    4360                 :            :          * atomic contexts and is allowed to schedule (with the special case
    4361                 :            :          * of oops_in_progress, but that isn't of any concern for this
    4362                 :            :          * function. --BenH.
    4363                 :            :          */
    4364                 :          3 :         might_sleep();
    4365                 :            : 
    4366                 :            :         /* This isn't perfectly race free, but a race here would be mostly harmless,
    4367                 :            :          * at worse, we'll do a spurrious blank and it's unlikely
    4368                 :            :          */
    4369                 :          3 :         del_timer(&console_timer);
    4370                 :          3 :         blank_timer_expired = 0;
    4371                 :            : 
    4372                 :          3 :         if (ignore_poke || !vc_cons[fg_console].d || vc_cons[fg_console].d->vc_mode == KD_GRAPHICS)
    4373                 :          3 :                 return;
    4374                 :          1 :         if (console_blanked)
    4375                 :            :                 unblank_screen();
    4376                 :          1 :         else if (blankinterval) {
    4377                 :          0 :                 mod_timer(&console_timer, jiffies + (blankinterval * HZ));
    4378                 :          0 :                 blank_state = blank_normal_wait;
    4379                 :            :         }
    4380                 :            : }
    4381                 :            : 
    4382                 :            : /*
    4383                 :            :  *      Palettes
    4384                 :            :  */
    4385                 :            : 
    4386                 :          3 : static void set_palette(struct vc_data *vc)
    4387                 :            : {
    4388                 :          3 :         WARN_CONSOLE_UNLOCKED();
    4389                 :            : 
    4390                 :          3 :         if (vc->vc_mode != KD_GRAPHICS && vc->vc_sw->con_set_palette)
    4391                 :          3 :                 vc->vc_sw->con_set_palette(vc, color_table);
    4392                 :          3 : }
    4393                 :            : 
    4394                 :            : /*
    4395                 :            :  * Load palette into the DAC registers. arg points to a colour
    4396                 :            :  * map, 3 bytes per colour, 16 colours, range from 0 to 255.
    4397                 :            :  */
    4398                 :            : 
    4399                 :          2 : int con_set_cmap(unsigned char __user *arg)
    4400                 :            : {
    4401                 :            :         int i, j, k;
    4402                 :            :         unsigned char colormap[3*16];
    4403                 :            : 
    4404                 :          2 :         if (copy_from_user(colormap, arg, sizeof(colormap)))
    4405                 :            :                 return -EFAULT;
    4406                 :            : 
    4407                 :          2 :         console_lock();
    4408                 :          2 :         for (i = k = 0; i < 16; i++) {
    4409                 :          2 :                 default_red[i] = colormap[k++];
    4410                 :          2 :                 default_grn[i] = colormap[k++];
    4411                 :          2 :                 default_blu[i] = colormap[k++];
    4412                 :            :         }
    4413                 :          2 :         for (i = 0; i < MAX_NR_CONSOLES; i++) {
    4414                 :          2 :                 if (!vc_cons_allocated(i))
    4415                 :          2 :                         continue;
    4416                 :          2 :                 for (j = k = 0; j < 16; j++) {
    4417                 :          2 :                         vc_cons[i].d->vc_palette[k++] = default_red[j];
    4418                 :          2 :                         vc_cons[i].d->vc_palette[k++] = default_grn[j];
    4419                 :          2 :                         vc_cons[i].d->vc_palette[k++] = default_blu[j];
    4420                 :            :                 }
    4421                 :          2 :                 set_palette(vc_cons[i].d);
    4422                 :            :         }
    4423                 :          2 :         console_unlock();
    4424                 :            : 
    4425                 :          2 :         return 0;
    4426                 :            : }
    4427                 :            : 
    4428                 :          2 : int con_get_cmap(unsigned char __user *arg)
    4429                 :            : {
    4430                 :            :         int i, k;
    4431                 :            :         unsigned char colormap[3*16];
    4432                 :            : 
    4433                 :          2 :         console_lock();
    4434                 :          2 :         for (i = k = 0; i < 16; i++) {
    4435                 :          2 :                 colormap[k++] = default_red[i];
    4436                 :          2 :                 colormap[k++] = default_grn[i];
    4437                 :          2 :                 colormap[k++] = default_blu[i];
    4438                 :            :         }
    4439                 :          2 :         console_unlock();
    4440                 :            : 
    4441                 :          2 :         if (copy_to_user(arg, colormap, sizeof(colormap)))
    4442                 :            :                 return -EFAULT;
    4443                 :            : 
    4444                 :          2 :         return 0;
    4445                 :            : }
    4446                 :            : 
    4447                 :          3 : void reset_palette(struct vc_data *vc)
    4448                 :            : {
    4449                 :            :         int j, k;
    4450                 :          3 :         for (j=k=0; j<16; j++) {
    4451                 :          3 :                 vc->vc_palette[k++] = default_red[j];
    4452                 :          3 :                 vc->vc_palette[k++] = default_grn[j];
    4453                 :          3 :                 vc->vc_palette[k++] = default_blu[j];
    4454                 :            :         }
    4455                 :          3 :         set_palette(vc);
    4456                 :          3 : }
    4457                 :            : 
    4458                 :            : /*
    4459                 :            :  *  Font switching
    4460                 :            :  *
    4461                 :            :  *  Currently we only support fonts up to 32 pixels wide, at a maximum height
    4462                 :            :  *  of 32 pixels. Userspace fontdata is stored with 32 bytes (shorts/ints, 
    4463                 :            :  *  depending on width) reserved for each character which is kinda wasty, but 
    4464                 :            :  *  this is done in order to maintain compatibility with the EGA/VGA fonts. It 
    4465                 :            :  *  is up to the actual low-level console-driver convert data into its favorite
    4466                 :            :  *  format (maybe we should add a `fontoffset' field to the `display'
    4467                 :            :  *  structure so we won't have to convert the fontdata all the time.
    4468                 :            :  *  /Jes
    4469                 :            :  */
    4470                 :            : 
    4471                 :            : #define max_font_size 65536
    4472                 :            : 
    4473                 :          0 : static int con_font_get(struct vc_data *vc, struct console_font_op *op)
    4474                 :            : {
    4475                 :            :         struct console_font font;
    4476                 :            :         int rc = -EINVAL;
    4477                 :            :         int c;
    4478                 :            : 
    4479                 :          0 :         if (op->data) {
    4480                 :          0 :                 font.data = kmalloc(max_font_size, GFP_KERNEL);
    4481                 :          0 :                 if (!font.data)
    4482                 :            :                         return -ENOMEM;
    4483                 :            :         } else
    4484                 :          0 :                 font.data = NULL;
    4485                 :            : 
    4486                 :          0 :         console_lock();
    4487                 :          0 :         if (vc->vc_mode != KD_TEXT)
    4488                 :            :                 rc = -EINVAL;
    4489                 :          0 :         else if (vc->vc_sw->con_font_get)
    4490                 :          0 :                 rc = vc->vc_sw->con_font_get(vc, &font);
    4491                 :            :         else
    4492                 :            :                 rc = -ENOSYS;
    4493                 :          0 :         console_unlock();
    4494                 :            : 
    4495                 :          0 :         if (rc)
    4496                 :            :                 goto out;
    4497                 :            : 
    4498                 :          0 :         c = (font.width+7)/8 * 32 * font.charcount;
    4499                 :            : 
    4500                 :          0 :         if (op->data && font.charcount > op->charcount)
    4501                 :            :                 rc = -ENOSPC;
    4502                 :          0 :         if (!(op->flags & KD_FONT_FLAG_OLD)) {
    4503                 :          0 :                 if (font.width > op->width || font.height > op->height) 
    4504                 :            :                         rc = -ENOSPC;
    4505                 :            :         } else {
    4506                 :          0 :                 if (font.width != 8)
    4507                 :            :                         rc = -EIO;
    4508                 :          0 :                 else if ((op->height && font.height > op->height) ||
    4509                 :          0 :                          font.height > 32)
    4510                 :            :                         rc = -ENOSPC;
    4511                 :            :         }
    4512                 :          0 :         if (rc)
    4513                 :            :                 goto out;
    4514                 :            : 
    4515                 :          0 :         op->height = font.height;
    4516                 :          0 :         op->width = font.width;
    4517                 :          0 :         op->charcount = font.charcount;
    4518                 :            : 
    4519                 :          0 :         if (op->data && copy_to_user(op->data, font.data, c))
    4520                 :            :                 rc = -EFAULT;
    4521                 :            : 
    4522                 :            : out:
    4523                 :          0 :         kfree(font.data);
    4524                 :          0 :         return rc;
    4525                 :            : }
    4526                 :            : 
    4527                 :          0 : static int con_font_set(struct vc_data *vc, struct console_font_op *op)
    4528                 :            : {
    4529                 :            :         struct console_font font;
    4530                 :            :         int rc = -EINVAL;
    4531                 :            :         int size;
    4532                 :            : 
    4533                 :          0 :         if (vc->vc_mode != KD_TEXT)
    4534                 :            :                 return -EINVAL;
    4535                 :          0 :         if (!op->data)
    4536                 :            :                 return -EINVAL;
    4537                 :          0 :         if (op->charcount > 512)
    4538                 :            :                 return -EINVAL;
    4539                 :          0 :         if (op->width <= 0 || op->width > 32 || op->height > 32)
    4540                 :            :                 return -EINVAL;
    4541                 :          0 :         size = (op->width+7)/8 * 32 * op->charcount;
    4542                 :          0 :         if (size > max_font_size)
    4543                 :            :                 return -ENOSPC;
    4544                 :            : 
    4545                 :          0 :         font.data = memdup_user(op->data, size);
    4546                 :          0 :         if (IS_ERR(font.data))
    4547                 :          0 :                 return PTR_ERR(font.data);
    4548                 :            : 
    4549                 :          0 :         if (!op->height) {           /* Need to guess font height [compat] */
    4550                 :            :                 int h, i;
    4551                 :            :                 u8 *charmap = font.data;
    4552                 :            : 
    4553                 :            :                 /*
    4554                 :            :                  * If from KDFONTOP ioctl, don't allow things which can be done
    4555                 :            :                  * in userland,so that we can get rid of this soon
    4556                 :            :                  */
    4557                 :          0 :                 if (!(op->flags & KD_FONT_FLAG_OLD)) {
    4558                 :          0 :                         kfree(font.data);
    4559                 :          0 :                         return -EINVAL;
    4560                 :            :                 }
    4561                 :            : 
    4562                 :          0 :                 for (h = 32; h > 0; h--)
    4563                 :          0 :                         for (i = 0; i < op->charcount; i++)
    4564                 :          0 :                                 if (charmap[32*i+h-1])
    4565                 :            :                                         goto nonzero;
    4566                 :            : 
    4567                 :          0 :                 kfree(font.data);
    4568                 :          0 :                 return -EINVAL;
    4569                 :            : 
    4570                 :            :         nonzero:
    4571                 :          0 :                 op->height = h;
    4572                 :            :         }
    4573                 :            : 
    4574                 :          0 :         font.charcount = op->charcount;
    4575                 :          0 :         font.width = op->width;
    4576                 :          0 :         font.height = op->height;
    4577                 :            : 
    4578                 :          0 :         console_lock();
    4579                 :          0 :         if (vc->vc_mode != KD_TEXT)
    4580                 :            :                 rc = -EINVAL;
    4581                 :          0 :         else if (vc->vc_sw->con_font_set)
    4582                 :          0 :                 rc = vc->vc_sw->con_font_set(vc, &font, op->flags);
    4583                 :            :         else
    4584                 :            :                 rc = -ENOSYS;
    4585                 :          0 :         console_unlock();
    4586                 :          0 :         kfree(font.data);
    4587                 :          0 :         return rc;
    4588                 :            : }
    4589                 :            : 
    4590                 :          0 : static int con_font_default(struct vc_data *vc, struct console_font_op *op)
    4591                 :            : {
    4592                 :          0 :         struct console_font font = {.width = op->width, .height = op->height};
    4593                 :            :         char name[MAX_FONT_NAME];
    4594                 :            :         char *s = name;
    4595                 :            :         int rc;
    4596                 :            : 
    4597                 :            : 
    4598                 :          0 :         if (!op->data)
    4599                 :            :                 s = NULL;
    4600                 :          0 :         else if (strncpy_from_user(name, op->data, MAX_FONT_NAME - 1) < 0)
    4601                 :            :                 return -EFAULT;
    4602                 :            :         else
    4603                 :          0 :                 name[MAX_FONT_NAME - 1] = 0;
    4604                 :            : 
    4605                 :          0 :         console_lock();
    4606                 :          0 :         if (vc->vc_mode != KD_TEXT) {
    4607                 :          0 :                 console_unlock();
    4608                 :          0 :                 return -EINVAL;
    4609                 :            :         }
    4610                 :          0 :         if (vc->vc_sw->con_font_default)
    4611                 :          0 :                 rc = vc->vc_sw->con_font_default(vc, &font, s);
    4612                 :            :         else
    4613                 :            :                 rc = -ENOSYS;
    4614                 :          0 :         console_unlock();
    4615                 :          0 :         if (!rc) {
    4616                 :          0 :                 op->width = font.width;
    4617                 :          0 :                 op->height = font.height;
    4618                 :            :         }
    4619                 :          0 :         return rc;
    4620                 :            : }
    4621                 :            : 
    4622                 :          0 : static int con_font_copy(struct vc_data *vc, struct console_font_op *op)
    4623                 :            : {
    4624                 :          0 :         int con = op->height;
    4625                 :            :         int rc;
    4626                 :            : 
    4627                 :            : 
    4628                 :          0 :         console_lock();
    4629                 :          0 :         if (vc->vc_mode != KD_TEXT)
    4630                 :            :                 rc = -EINVAL;
    4631                 :          0 :         else if (!vc->vc_sw->con_font_copy)
    4632                 :            :                 rc = -ENOSYS;
    4633                 :          0 :         else if (con < 0 || !vc_cons_allocated(con))
    4634                 :            :                 rc = -ENOTTY;
    4635                 :          0 :         else if (con == vc->vc_num)  /* nothing to do */
    4636                 :            :                 rc = 0;
    4637                 :            :         else
    4638                 :          0 :                 rc = vc->vc_sw->con_font_copy(vc, con);
    4639                 :          0 :         console_unlock();
    4640                 :          0 :         return rc;
    4641                 :            : }
    4642                 :            : 
    4643                 :          0 : int con_font_op(struct vc_data *vc, struct console_font_op *op)
    4644                 :            : {
    4645                 :          0 :         switch (op->op) {
    4646                 :            :         case KD_FONT_OP_SET:
    4647                 :          0 :                 return con_font_set(vc, op);
    4648                 :            :         case KD_FONT_OP_GET:
    4649                 :          0 :                 return con_font_get(vc, op);
    4650                 :            :         case KD_FONT_OP_SET_DEFAULT:
    4651                 :          0 :                 return con_font_default(vc, op);
    4652                 :            :         case KD_FONT_OP_COPY:
    4653                 :          0 :                 return con_font_copy(vc, op);
    4654                 :            :         }
    4655                 :            :         return -ENOSYS;
    4656                 :            : }
    4657                 :            : 
    4658                 :            : /*
    4659                 :            :  *      Interface exported to selection and vcs.
    4660                 :            :  */
    4661                 :            : 
    4662                 :            : /* used by selection */
    4663                 :          0 : u16 screen_glyph(struct vc_data *vc, int offset)
    4664                 :            : {
    4665                 :          0 :         u16 w = scr_readw(screenpos(vc, offset, 1));
    4666                 :          0 :         u16 c = w & 0xff;
    4667                 :            : 
    4668                 :          0 :         if (w & vc->vc_hi_font_mask)
    4669                 :          0 :                 c |= 0x100;
    4670                 :          0 :         return c;
    4671                 :            : }
    4672                 :            : EXPORT_SYMBOL_GPL(screen_glyph);
    4673                 :            : 
    4674                 :          0 : u32 screen_glyph_unicode(struct vc_data *vc, int n)
    4675                 :            : {
    4676                 :          0 :         struct uni_screen *uniscr = get_vc_uniscr(vc);
    4677                 :            : 
    4678                 :          0 :         if (uniscr)
    4679                 :          0 :                 return uniscr->lines[n / vc->vc_cols][n % vc->vc_cols];
    4680                 :          0 :         return inverse_translate(vc, screen_glyph(vc, n * 2), 1);
    4681                 :            : }
    4682                 :            : EXPORT_SYMBOL_GPL(screen_glyph_unicode);
    4683                 :            : 
    4684                 :            : /* used by vcs - note the word offset */
    4685                 :          0 : unsigned short *screen_pos(struct vc_data *vc, int w_offset, int viewed)
    4686                 :            : {
    4687                 :          0 :         return screenpos(vc, 2 * w_offset, viewed);
    4688                 :            : }
    4689                 :            : EXPORT_SYMBOL_GPL(screen_pos);
    4690                 :            : 
    4691                 :          0 : void getconsxy(struct vc_data *vc, unsigned char *p)
    4692                 :            : {
    4693                 :            :         /* clamp values if they don't fit */
    4694                 :          0 :         p[0] = min(vc->vc_x, 0xFFu);
    4695                 :          0 :         p[1] = min(vc->vc_y, 0xFFu);
    4696                 :          0 : }
    4697                 :            : 
    4698                 :          0 : void putconsxy(struct vc_data *vc, unsigned char *p)
    4699                 :            : {
    4700                 :          0 :         hide_cursor(vc);
    4701                 :          0 :         gotoxy(vc, p[0], p[1]);
    4702                 :          0 :         set_cursor(vc);
    4703                 :          0 : }
    4704                 :            : 
    4705                 :          0 : u16 vcs_scr_readw(struct vc_data *vc, const u16 *org)
    4706                 :            : {
    4707                 :          0 :         if ((unsigned long)org == vc->vc_pos && softcursor_original != -1)
    4708                 :          0 :                 return softcursor_original;
    4709                 :          0 :         return scr_readw(org);
    4710                 :            : }
    4711                 :            : 
    4712                 :          0 : void vcs_scr_writew(struct vc_data *vc, u16 val, u16 *org)
    4713                 :            : {
    4714                 :          0 :         scr_writew(val, org);
    4715                 :          0 :         if ((unsigned long)org == vc->vc_pos) {
    4716                 :          0 :                 softcursor_original = -1;
    4717                 :          0 :                 add_softcursor(vc);
    4718                 :            :         }
    4719                 :          0 : }
    4720                 :            : 
    4721                 :          0 : void vcs_scr_updated(struct vc_data *vc)
    4722                 :            : {
    4723                 :            :         notify_update(vc);
    4724                 :          0 : }
    4725                 :            : 
    4726                 :          0 : void vc_scrolldelta_helper(struct vc_data *c, int lines,
    4727                 :            :                 unsigned int rolled_over, void *base, unsigned int size)
    4728                 :            : {
    4729                 :          0 :         unsigned long ubase = (unsigned long)base;
    4730                 :          0 :         ptrdiff_t scr_end = (void *)c->vc_scr_end - base;
    4731                 :          0 :         ptrdiff_t vorigin = (void *)c->vc_visible_origin - base;
    4732                 :          0 :         ptrdiff_t origin = (void *)c->vc_origin - base;
    4733                 :          0 :         int margin = c->vc_size_row * 4;
    4734                 :            :         int from, wrap, from_off, avail;
    4735                 :            : 
    4736                 :            :         /* Turn scrollback off */
    4737                 :          0 :         if (!lines) {
    4738                 :          0 :                 c->vc_visible_origin = c->vc_origin;
    4739                 :          0 :                 return;
    4740                 :            :         }
    4741                 :            : 
    4742                 :            :         /* Do we have already enough to allow jumping from 0 to the end? */
    4743                 :          0 :         if (rolled_over > scr_end + margin) {
    4744                 :            :                 from = scr_end;
    4745                 :          0 :                 wrap = rolled_over + c->vc_size_row;
    4746                 :            :         } else {
    4747                 :            :                 from = 0;
    4748                 :          0 :                 wrap = size;
    4749                 :            :         }
    4750                 :            : 
    4751                 :          0 :         from_off = (vorigin - from + wrap) % wrap + lines * c->vc_size_row;
    4752                 :          0 :         avail = (origin - from + wrap) % wrap;
    4753                 :            : 
    4754                 :            :         /* Only a little piece would be left? Show all incl. the piece! */
    4755                 :          0 :         if (avail < 2 * margin)
    4756                 :            :                 margin = 0;
    4757                 :          0 :         if (from_off < margin)
    4758                 :            :                 from_off = 0;
    4759                 :          0 :         if (from_off > avail - margin)
    4760                 :            :                 from_off = avail;
    4761                 :            : 
    4762                 :          0 :         c->vc_visible_origin = ubase + (from + from_off) % wrap;
    4763                 :            : }
    4764                 :            : EXPORT_SYMBOL_GPL(vc_scrolldelta_helper);
    4765                 :            : 
    4766                 :            : /*
    4767                 :            :  *      Visible symbols for modules
    4768                 :            :  */
    4769                 :            : 
    4770                 :            : EXPORT_SYMBOL(color_table);
    4771                 :            : EXPORT_SYMBOL(default_red);
    4772                 :            : EXPORT_SYMBOL(default_grn);
    4773                 :            : EXPORT_SYMBOL(default_blu);
    4774                 :            : EXPORT_SYMBOL(update_region);
    4775                 :            : EXPORT_SYMBOL(redraw_screen);
    4776                 :            : EXPORT_SYMBOL(vc_resize);
    4777                 :            : EXPORT_SYMBOL(fg_console);
    4778                 :            : EXPORT_SYMBOL(console_blank_hook);
    4779                 :            : EXPORT_SYMBOL(console_blanked);
    4780                 :            : EXPORT_SYMBOL(vc_cons);
    4781                 :            : EXPORT_SYMBOL(global_cursor_default);
    4782                 :            : #ifndef VT_SINGLE_DRIVER
    4783                 :            : EXPORT_SYMBOL(give_up_console);
    4784                 :            : #endif
    

Generated by: LCOV version 1.14