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