LCOV - code coverage report
Current view: top level - tty/vt - vt.c (source / functions) Coverage Total Hit
Test: TTY Combined Coverage Lines: 0.0 % 2691 0
Test Date: 2025-08-26 15:45:50 Functions: 0.0 % 173 0

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

Generated by: LCOV version 2.0-1