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 *      Low-Level Functions
 257 */
 258
 259#define IS_FG(vc)       ((vc)->vc_num == fg_console)
 260
 261#ifdef VT_BUF_VRAM_ONLY
 262#define DO_UPDATE(vc)   0
 263#else
 264#define DO_UPDATE(vc)   (CON_IS_VISIBLE(vc) && !console_blanked)
 265#endif
 266
 267static inline unsigned short *screenpos(struct vc_data *vc, int offset, int viewed)
 268{
 269        unsigned short *p;
 270        
 271        if (!viewed)
 272                p = (unsigned short *)(vc->vc_origin + offset);
 273        else if (!vc->vc_sw->con_screen_pos)
 274                p = (unsigned short *)(vc->vc_visible_origin + offset);
 275        else
 276                p = vc->vc_sw->con_screen_pos(vc, offset);
 277        return p;
 278}
 279
 280static inline void scrolldelta(int lines)
 281{
 282        scrollback_delta += lines;
 283        schedule_console_callback();
 284}
 285
 286void schedule_console_callback(void)
 287{
 288        schedule_work(&console_work);
 289}
 290
 291static void scrup(struct vc_data *vc, unsigned int t, unsigned int b, int nr)
 292{
 293        unsigned short *d, *s;
 294
 295        if (t+nr >= b)
 296                nr = b - t - 1;
 297        if (b > vc->vc_rows || t >= b || nr < 1)
 298                return;
 299        if (CON_IS_VISIBLE(vc) && vc->vc_sw->con_scroll(vc, t, b, SM_UP, nr))
 300                return;
 301        d = (unsigned short *)(vc->vc_origin + vc->vc_size_row * t);
 302        s = (unsigned short *)(vc->vc_origin + vc->vc_size_row * (t + nr));
 303        scr_memmovew(d, s, (b - t - nr) * vc->vc_size_row);
 304        scr_memsetw(d + (b - t - nr) * vc->vc_cols, vc->vc_video_erase_char,
 305                    vc->vc_size_row * nr);
 306}
 307
 308static void scrdown(struct vc_data *vc, unsigned int t, unsigned int b, int nr)
 309{
 310        unsigned short *s;
 311        unsigned int step;
 312
 313        if (t+nr >= b)
 314                nr = b - t - 1;
 315        if (b > vc->vc_rows || t >= b || nr < 1)
 316                return;
 317        if (CON_IS_VISIBLE(vc) && vc->vc_sw->con_scroll(vc, t, b, SM_DOWN, nr))
 318                return;
 319        s = (unsigned short *)(vc->vc_origin + vc->vc_size_row * t);
 320        step = vc->vc_cols * nr;
 321        scr_memmovew(s + step, s, (b - t - nr) * vc->vc_size_row);
 322        scr_memsetw(s, vc->vc_video_erase_char, 2 * step);
 323}
 324
 325static void do_update_region(struct vc_data *vc, unsigned long start, int count)
 326{
 327#ifndef VT_BUF_VRAM_ONLY
 328        unsigned int xx, yy, offset;
 329        u16 *p;
 330
 331        p = (u16 *) start;
 332        if (!vc->vc_sw->con_getxy) {
 333                offset = (start - vc->vc_origin) / 2;
 334                xx = offset % vc->vc_cols;
 335                yy = offset / vc->vc_cols;
 336        } else {
 337                int nxx, nyy;
 338                start = vc->vc_sw->con_getxy(vc, start, &nxx, &nyy);
 339                xx = nxx; yy = nyy;
 340        }
 341        for(;;) {
 342                u16 attrib = scr_readw(p) & 0xff00;
 343                int startx = xx;
 344                u16 *q = p;
 345                while (xx < vc->vc_cols && count) {
 346                        if (attrib != (scr_readw(p) & 0xff00)) {
 347                                if (p > q)
 348                                        vc->vc_sw->con_putcs(vc, q, p-q, yy, startx);
 349                                startx = xx;
 350                                q = p;
 351                                attrib = scr_readw(p) & 0xff00;
 352                        }
 353                        p++;
 354                        xx++;
 355                        count--;
 356                }
 357                if (p > q)
 358                        vc->vc_sw->con_putcs(vc, q, p-q, yy, startx);
 359                if (!count)
 360                        break;
 361                xx = 0;
 362                yy++;
 363                if (vc->vc_sw->con_getxy) {
 364                        p = (u16 *)start;
 365                        start = vc->vc_sw->con_getxy(vc, start, NULL, NULL);
 366                }
 367        }
 368#endif
 369}
 370
 371void update_region(struct vc_data *vc, unsigned long start, int count)
 372{
 373        WARN_CONSOLE_UNLOCKED();
 374
 375        if (DO_UPDATE(vc)) {
 376                hide_cursor(vc);
 377                do_update_region(vc, start, count);
 378                set_cursor(vc);
 379        }
 380}
 381
 382/* Structure of attributes is hardware-dependent */
 383
 384static u8 build_attr(struct vc_data *vc, u8 _color, u8 _intensity, u8 _blink,
 385    u8 _underline, u8 _reverse, u8 _italic)
 386{
 387        if (vc->vc_sw->con_build_attr)
 388                return vc->vc_sw->con_build_attr(vc, _color, _intensity,
 389                       _blink, _underline, _reverse, _italic);
 390
 391#ifndef VT_BUF_VRAM_ONLY
 392/*
 393 * ++roman: I completely changed the attribute format for monochrome
 394 * mode (!can_do_color). The formerly used MDA (monochrome display
 395 * adapter) format didn't allow the combination of certain effects.
 396 * Now the attribute is just a bit vector:
 397 *  Bit 0..1: intensity (0..2)
 398 *  Bit 2   : underline
 399 *  Bit 3   : reverse
 400 *  Bit 7   : blink
 401 */
 402        {
 403        u8 a = _color;
 404        if (!vc->vc_can_do_color)
 405                return _intensity |
 406                       (_italic ? 2 : 0) |
 407                       (_underline ? 4 : 0) |
 408                       (_reverse ? 8 : 0) |
 409                       (_blink ? 0x80 : 0);
 410        if (_italic)
 411                a = (a & 0xF0) | vc->vc_itcolor;
 412        else if (_underline)
 413                a = (a & 0xf0) | vc->vc_ulcolor;
 414        else if (_intensity == 0)
 415                a = (a & 0xf0) | vc->vc_ulcolor;
 416        if (_reverse)
 417                a = ((a) & 0x88) | ((((a) >> 4) | ((a) << 4)) & 0x77);
 418        if (_blink)
 419                a ^= 0x80;
 420        if (_intensity == 2)
 421                a ^= 0x08;
 422        if (vc->vc_hi_font_mask == 0x100)
 423                a <<= 1;
 424        return a;
 425        }
 426#else
 427        return 0;
 428#endif
 429}
 430
 431static void update_attr(struct vc_data *vc)
 432{
 433        vc->vc_attr = build_attr(vc, vc->vc_color, vc->vc_intensity,
 434                      vc->vc_blink, vc->vc_underline,
 435                      vc->vc_reverse ^ vc->vc_decscnm, vc->vc_italic);
 436        vc->vc_video_erase_char = (build_attr(vc, vc->vc_color, 1, vc->vc_blink, 0, vc->vc_decscnm, 0) << 8) | ' ';
 437}
 438
 439/* Note: inverting the screen twice should revert to the original state */
 440void invert_screen(struct vc_data *vc, int offset, int count, int viewed)
 441{
 442        unsigned short *p;
 443
 444        WARN_CONSOLE_UNLOCKED();
 445
 446        count /= 2;
 447        p = screenpos(vc, offset, viewed);
 448        if (vc->vc_sw->con_invert_region)
 449                vc->vc_sw->con_invert_region(vc, p, count);
 450#ifndef VT_BUF_VRAM_ONLY
 451        else {
 452                u16 *q = p;
 453                int cnt = count;
 454                u16 a;
 455
 456                if (!vc->vc_can_do_color) {
 457                        while (cnt--) {
 458                            a = scr_readw(q);
 459                            a ^= 0x0800;
 460                            scr_writew(a, q);
 461                            q++;
 462                        }
 463                } else if (vc->vc_hi_font_mask == 0x100) {
 464                        while (cnt--) {
 465                                a = scr_readw(q);
 466                                a = ((a) & 0x11ff) | (((a) & 0xe000) >> 4) | (((a) & 0x0e00) << 4);
 467                                scr_writew(a, q);
 468                                q++;
 469                        }
 470                } else {
 471                        while (cnt--) {
 472                                a = scr_readw(q);
 473                                a = ((a) & 0x88ff) | (((a) & 0x7000) >> 4) | (((a) & 0x0700) << 4);
 474                                scr_writew(a, q);
 475                                q++;
 476                        }
 477                }
 478        }
 479#endif
 480        if (DO_UPDATE(vc))
 481                do_update_region(vc, (unsigned long) p, count);
 482}
 483
 484/* used by selection: complement pointer position */
 485void complement_pos(struct vc_data *vc, int offset)
 486{
 487        static int old_offset = -1;
 488        static unsigned short old;
 489        static unsigned short oldx, oldy;
 490
 491        WARN_CONSOLE_UNLOCKED();
 492
 493        if (old_offset != -1 && old_offset >= 0 &&
 494            old_offset < vc->vc_screenbuf_size) {
 495                scr_writew(old, screenpos(vc, old_offset, 1));
 496                if (DO_UPDATE(vc))
 497                        vc->vc_sw->con_putc(vc, old, oldy, oldx);
 498        }
 499
 500        old_offset = offset;
 501
 502        if (offset != -1 && offset >= 0 &&
 503            offset < vc->vc_screenbuf_size) {
 504                unsigned short new;
 505                unsigned short *p;
 506                p = screenpos(vc, offset, 1);
 507                old = scr_readw(p);
 508                new = old ^ vc->vc_complement_mask;
 509                scr_writew(new, p);
 510                if (DO_UPDATE(vc)) {
 511                        oldx = (offset >> 1) % vc->vc_cols;
 512                        oldy = (offset >> 1) / vc->vc_cols;
 513                        vc->vc_sw->con_putc(vc, new, oldy, oldx);
 514                }
 515        }
 516
 517}
 518
 519static void insert_char(struct vc_data *vc, unsigned int nr)
 520{
 521        unsigned short *p, *q = (unsigned short *)vc->vc_pos;
 522
 523        p = q + vc->vc_cols - nr - vc->vc_x;
 524        while (--p >= q)
 525                scr_writew(scr_readw(p), p + nr);
 526        scr_memsetw(q, vc->vc_video_erase_char, nr * 2);
 527        vc->vc_need_wrap = 0;
 528        if (DO_UPDATE(vc)) {
 529                unsigned short oldattr = vc->vc_attr;
 530                vc->vc_sw->con_bmove(vc, vc->vc_y, vc->vc_x, vc->vc_y, vc->vc_x + nr, 1,
 531                                     vc->vc_cols - vc->vc_x - nr);
 532                vc->vc_attr = vc->vc_video_erase_char >> 8;
 533                while (nr--)
 534                        vc->vc_sw->con_putc(vc, vc->vc_video_erase_char, vc->vc_y, vc->vc_x + nr);
 535                vc->vc_attr = oldattr;
 536        }
 537}
 538
 539static void delete_char(struct vc_data *vc, unsigned int nr)
 540{
 541        unsigned int i = vc->vc_x;
 542        unsigned short *p = (unsigned short *)vc->vc_pos;
 543
 544        while (++i <= vc->vc_cols - nr) {
 545                scr_writew(scr_readw(p+nr), p);
 546                p++;
 547        }
 548        scr_memsetw(p, vc->vc_video_erase_char, nr * 2);
 549        vc->vc_need_wrap = 0;
 550        if (DO_UPDATE(vc)) {
 551                unsigned short oldattr = vc->vc_attr;
 552                vc->vc_sw->con_bmove(vc, vc->vc_y, vc->vc_x + nr, vc->vc_y, vc->vc_x, 1,
 553                                     vc->vc_cols - vc->vc_x - nr);
 554                vc->vc_attr = vc->vc_video_erase_char >> 8;
 555                while (nr--)
 556                        vc->vc_sw->con_putc(vc, vc->vc_video_erase_char, vc->vc_y,
 557                                     vc->vc_cols - 1 - nr);
 558                vc->vc_attr = oldattr;
 559        }
 560}
 561
 562static int softcursor_original;
 563
 564static void add_softcursor(struct vc_data *vc)
 565{
 566        int i = scr_readw((u16 *) vc->vc_pos);
 567        u32 type = vc->vc_cursor_type;
 568
 569        if (! (type & 0x10)) return;
 570        if (softcursor_original != -1) return;
 571        softcursor_original = i;
 572        i |= ((type >> 8) & 0xff00 );
 573        i ^= ((type) & 0xff00 );
 574        if ((type & 0x20) && ((softcursor_original & 0x7000) == (i & 0x7000))) i ^= 0x7000;
 575        if ((type & 0x40) && ((i & 0x700) == ((i & 0x7000) >> 4))) i ^= 0x0700;
 576        scr_writew(i, (u16 *) vc->vc_pos);
 577        if (DO_UPDATE(vc))
 578                vc->vc_sw->con_putc(vc, i, vc->vc_y, vc->vc_x);
 579}
 580
 581static void hide_softcursor(struct vc_data *vc)
 582{
 583        if (softcursor_original != -1) {
 584                scr_writew(softcursor_original, (u16 *)vc->vc_pos);
 585                if (DO_UPDATE(vc))
 586                        vc->vc_sw->con_putc(vc, softcursor_original,
 587                                        vc->vc_y, vc->vc_x);
 588                softcursor_original = -1;
 589        }
 590}
 591
 592static void hide_cursor(struct vc_data *vc)
 593{
 594        if (vc == sel_cons)
 595                clear_selection();
 596        vc->vc_sw->con_cursor(vc, CM_ERASE);
 597        hide_softcursor(vc);
 598}
 599
 600static void set_cursor(struct vc_data *vc)
 601{
 602        if (!IS_FG(vc) || console_blanked ||
 603            vc->vc_mode == KD_GRAPHICS)
 604                return;
 605        if (vc->vc_deccm) {
 606                if (vc == sel_cons)
 607                        clear_selection();
 608                add_softcursor(vc);
 609                if ((vc->vc_cursor_type & 0x0f) != 1)
 610                        vc->vc_sw->con_cursor(vc, CM_DRAW);
 611        } else
 612                hide_cursor(vc);
 613}
 614
 615static void set_origin(struct vc_data *vc)
 616{
 617        WARN_CONSOLE_UNLOCKED();
 618
 619        if (!CON_IS_VISIBLE(vc) ||
 620            !vc->vc_sw->con_set_origin ||
 621            !vc->vc_sw->con_set_origin(vc))
 622                vc->vc_origin = (unsigned long)vc->vc_screenbuf;
 623        vc->vc_visible_origin = vc->vc_origin;
 624        vc->vc_scr_end = vc->vc_origin + vc->vc_screenbuf_size;
 625        vc->vc_pos = vc->vc_origin + vc->vc_size_row * vc->vc_y + 2 * vc->vc_x;
 626}
 627
 628static inline void save_screen(struct vc_data *vc)
 629{
 630        WARN_CONSOLE_UNLOCKED();
 631
 632        if (vc->vc_sw->con_save_screen)
 633                vc->vc_sw->con_save_screen(vc);
 634}
 635
 636/*
 637 *      Redrawing of screen
 638 */
 639
 640static void clear_buffer_attributes(struct vc_data *vc)
 641{
 642        unsigned short *p = (unsigned short *)vc->vc_origin;
 643        int count = vc->vc_screenbuf_size / 2;
 644        int mask = vc->vc_hi_font_mask | 0xff;
 645
 646        for (; count > 0; count--, p++) {
 647                scr_writew((scr_readw(p)&mask) | (vc->vc_video_erase_char & ~mask), p);
 648        }
 649}
 650
 651void redraw_screen(struct vc_data *vc, int is_switch)
 652{
 653        int redraw = 0;
 654
 655        WARN_CONSOLE_UNLOCKED();
 656
 657        if (!vc) {
 658                /* strange ... */
 659                /* printk("redraw_screen: tty %d not allocated ??\n", new_console+1); */
 660                return;
 661        }
 662
 663        if (is_switch) {
 664                struct vc_data *old_vc = vc_cons[fg_console].d;
 665                if (old_vc == vc)
 666                        return;
 667                if (!CON_IS_VISIBLE(vc))
 668                        redraw = 1;
 669                *vc->vc_display_fg = vc;
 670                fg_console = vc->vc_num;
 671                hide_cursor(old_vc);
 672                if (!CON_IS_VISIBLE(old_vc)) {
 673                        save_screen(old_vc);
 674                        set_origin(old_vc);
 675                }
 676        } else {
 677                hide_cursor(vc);
 678                redraw = 1;
 679        }
 680
 681        if (redraw) {
 682                int update;
 683                int old_was_color = vc->vc_can_do_color;
 684
 685                set_origin(vc);
 686                update = vc->vc_sw->con_switch(vc);
 687                set_palette(vc);
 688                /*
 689                 * If console changed from mono<->color, the best we can do
 690                 * is to clear the buffer attributes. As it currently stands,
 691                 * rebuilding new attributes from the old buffer is not doable
 692                 * without overly complex code.
 693                 */
 694                if (old_was_color != vc->vc_can_do_color) {
 695                        update_attr(vc);
 696                        clear_buffer_attributes(vc);
 697                }
 698                if (update && vc->vc_mode != KD_GRAPHICS)
 699                        do_update_region(vc, vc->vc_origin, vc->vc_screenbuf_size / 2);
 700        }
 701        set_cursor(vc);
 702        if (is_switch) {
 703                set_leds();
 704                compute_shiftstate();
 705                notify_update(vc);
 706        }
 707}
 708
 709/*
 710 *      Allocation, freeing and resizing of VTs.
 711 */
 712
 713int vc_cons_allocated(unsigned int i)
 714{
 715        return (i < MAX_NR_CONSOLES && vc_cons[i].d);
 716}
 717
 718static void visual_init(struct vc_data *vc, int num, int init)
 719{
 720        /* ++Geert: vc->vc_sw->con_init determines console size */
 721        if (vc->vc_sw)
 722                module_put(vc->vc_sw->owner);
 723        vc->vc_sw = conswitchp;
 724#ifndef VT_SINGLE_DRIVER
 725        if (con_driver_map[num])
 726                vc->vc_sw = con_driver_map[num];
 727#endif
 728        __module_get(vc->vc_sw->owner);
 729        vc->vc_num = num;
 730        vc->vc_display_fg = &master_display_fg;
 731        vc->vc_uni_pagedir_loc = &vc->vc_uni_pagedir;
 732        vc->vc_uni_pagedir = 0;
 733        vc->vc_hi_font_mask = 0;
 734        vc->vc_complement_mask = 0;
 735        vc->vc_can_do_color = 0;
 736        vc->vc_sw->con_init(vc, init);
 737        if (!vc->vc_complement_mask)
 738                vc->vc_complement_mask = vc->vc_can_do_color ? 0x7700 : 0x0800;
 739        vc->vc_s_complement_mask = vc->vc_complement_mask;
 740        vc->vc_size_row = vc->vc_cols << 1;
 741        vc->vc_screenbuf_size = vc->vc_rows * vc->vc_size_row;
 742}
 743
 744int vc_allocate(unsigned int currcons)  /* return 0 on success */
 745{
 746        WARN_CONSOLE_UNLOCKED();
 747
 748        if (currcons >= MAX_NR_CONSOLES)
 749                return -ENXIO;
 750        if (!vc_cons[currcons].d) {
 751            struct vc_data *vc;
 752            struct vt_notifier_param param;
 753
 754            /* prevent users from taking too much memory */
 755            if (currcons >= MAX_NR_USER_CONSOLES && !capable(CAP_SYS_RESOURCE))
 756              return -EPERM;
 757
 758            /* due to the granularity of kmalloc, we waste some memory here */
 759            /* the alloc is done in two steps, to optimize the common situation
 760               of a 25x80 console (structsize=216, screenbuf_size=4000) */
 761            /* although the numbers above are not valid since long ago, the
 762               point is still up-to-date and the comment still has its value
 763               even if only as a historical artifact.  --mj, July 1998 */
 764            param.vc = vc = kzalloc(sizeof(struct vc_data), GFP_KERNEL);
 765            if (!vc)
 766                return -ENOMEM;
 767            vc_cons[currcons].d = vc;
 768            INIT_WORK(&vc_cons[currcons].SAK_work, vc_SAK);
 769            visual_init(vc, currcons, 1);
 770            if (!*vc->vc_uni_pagedir_loc)
 771                con_set_default_unimap(vc);
 772            vc->vc_screenbuf = kmalloc(vc->vc_screenbuf_size, GFP_KERNEL);
 773            if (!vc->vc_screenbuf) {
 774                kfree(vc);
 775                vc_cons[currcons].d = NULL;
 776                return -ENOMEM;
 777            }
 778            vc_init(vc, vc->vc_rows, vc->vc_cols, 1);
 779            vcs_make_sysfs(currcons);
 780            atomic_notifier_call_chain(&vt_notifier_list, VT_ALLOCATE, &param);
 781        }
 782        return 0;
 783}
 784
 785static inline int resize_screen(struct vc_data *vc, int width, int height,
 786                                int user)
 787{
 788        /* Resizes the resolution of the display adapater */
 789        int err = 0;
 790
 791        if (vc->vc_mode != KD_GRAPHICS && vc->vc_sw->con_resize)
 792                err = vc->vc_sw->con_resize(vc, width, height, user);
 793
 794        return err;
 795}
 796
 797/*
 798 * Change # of rows and columns (0 means unchanged/the size of fg_console)
 799 * [this is to be used together with some user program
 800 * like resize that changes the hardware videomode]
 801 */
 802#define VC_RESIZE_MAXCOL (32767)
 803#define VC_RESIZE_MAXROW (32767)
 804
 805/**
 806 *      vc_do_resize    -       resizing method for the tty
 807 *      @tty: tty being resized
 808 *      @real_tty: real tty (different to tty if a pty/tty pair)
 809 *      @vc: virtual console private data
 810 *      @cols: columns
 811 *      @lines: lines
 812 *
 813 *      Resize a virtual console, clipping according to the actual constraints.
 814 *      If the caller passes a tty structure then update the termios winsize
 815 *      information and perform any neccessary signal handling.
 816 *
 817 *      Caller must hold the console semaphore. Takes the termios mutex and
 818 *      ctrl_lock of the tty IFF a tty is passed.
 819 */
 820
 821static int vc_do_resize(struct tty_struct *tty, struct vc_data *vc,
 822                                unsigned int cols, unsigned int lines)
 823{
 824        unsigned long old_origin, new_origin, new_scr_end, rlth, rrem, err = 0;
 825        unsigned int old_cols, old_rows, old_row_size, old_screen_size;
 826        unsigned int new_cols, new_rows, new_row_size, new_screen_size;
 827        unsigned int end, user;
 828        unsigned short *newscreen;
 829
 830        WARN_CONSOLE_UNLOCKED();
 831
 832        if (!vc)
 833                return -ENXIO;
 834
 835        user = vc->vc_resize_user;
 836        vc->vc_resize_user = 0;
 837
 838        if (cols > VC_RESIZE_MAXCOL || lines > VC_RESIZE_MAXROW)
 839                return -EINVAL;
 840
 841        new_cols = (cols ? cols : vc->vc_cols);
 842        new_rows = (lines ? lines : vc->vc_rows);
 843        new_row_size = new_cols << 1;
 844        new_screen_size = new_row_size * new_rows;
 845
 846        if (new_cols == vc->vc_cols && new_rows == vc->vc_rows)
 847                return 0;
 848
 849        newscreen = kmalloc(new_screen_size, GFP_USER);
 850        if (!newscreen)
 851                return -ENOMEM;
 852
 853        old_rows = vc->vc_rows;
 854        old_cols = vc->vc_cols;
 855        old_row_size = vc->vc_size_row;
 856        old_screen_size = vc->vc_screenbuf_size;
 857
 858        err = resize_screen(vc, new_cols, new_rows, user);
 859        if (err) {
 860                kfree(newscreen);
 861                return err;
 862        }
 863
 864        vc->vc_rows = new_rows;
 865        vc->vc_cols = new_cols;
 866        vc->vc_size_row = new_row_size;
 867        vc->vc_screenbuf_size = new_screen_size;
 868
 869        rlth = min(old_row_size, new_row_size);
 870        rrem = new_row_size - rlth;
 871        old_origin = vc->vc_origin;
 872        new_origin = (long) newscreen;
 873        new_scr_end = new_origin + new_screen_size;
 874
 875        if (vc->vc_y > new_rows) {
 876                if (old_rows - vc->vc_y < new_rows) {
 877                        /*
 878                         * Cursor near the bottom, copy contents from the
 879                         * bottom of buffer
 880                         */
 881                        old_origin += (old_rows - new_rows) * old_row_size;
 882                        end = vc->vc_scr_end;
 883                } else {
 884                        /*
 885                         * Cursor is in no man's land, copy 1/2 screenful
 886                         * from the top and bottom of cursor position
 887                         */
 888                        old_origin += (vc->vc_y - new_rows/2) * old_row_size;
 889                        end = old_origin + (old_row_size * new_rows);
 890                }
 891        } else
 892                /*
 893                 * Cursor near the top, copy contents from the top of buffer
 894                 */
 895                end = (old_rows > new_rows) ? old_origin +
 896                        (old_row_size * new_rows) :
 897                        vc->vc_scr_end;
 898
 899        update_attr(vc);
 900
 901        while (old_origin < end) {
 902                scr_memcpyw((unsigned short *) new_origin,
 903                            (unsigned short *) old_origin, rlth);
 904                if (rrem)
 905                        scr_memsetw((void *)(new_origin + rlth),
 906                                    vc->vc_video_erase_char, rrem);
 907                old_origin += old_row_size;
 908                new_origin += new_row_size;
 909        }
 910        if (new_scr_end > new_origin)
 911                scr_memsetw((void *)new_origin, vc->vc_video_erase_char,
 912                            new_scr_end - new_origin);
 913        kfree(vc->vc_screenbuf);
 914        vc->vc_screenbuf = newscreen;
 915        vc->vc_screenbuf_size = new_screen_size;
 916        set_origin(vc);
 917
 918        /* do part of a reset_terminal() */
 919        vc->vc_top = 0;
 920        vc->vc_bottom = vc->vc_rows;
 921        gotoxy(vc, vc->vc_x, vc->vc_y);
 922        save_cur(vc);
 923
 924        if (tty) {
 925                /* Rewrite the requested winsize data with the actual
 926                   resulting sizes */
 927                struct winsize ws;
 928                memset(&ws, 0, sizeof(ws));
 929                ws.ws_row = vc->vc_rows;
 930                ws.ws_col = vc->vc_cols;
 931                ws.ws_ypixel = vc->vc_scan_lines;
 932                tty_do_resize(tty, &ws);
 933        }
 934
 935        if (CON_IS_VISIBLE(vc))
 936                update_screen(vc);
 937        vt_event_post(VT_EVENT_RESIZE, vc->vc_num, vc->vc_num);
 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                printk_once("con_write: tty %d not allocated\n", currcons+1);
2133            release_console_sem();
2134            return 0;
2135        }
2136        orig_buf = buf;
2137        orig_count = count;
2138
2139        himask = vc->vc_hi_font_mask;
2140        charmask = himask ? 0x1ff : 0xff;
2141
2142        /* undraw cursor first */
2143        if (IS_FG(vc))
2144                hide_cursor(vc);
2145
2146        param.vc = vc;
2147
2148        while (!tty->stopped && count) {
2149                int orig = *buf;
2150                c = orig;
2151                buf++;
2152                n++;
2153                count--;
2154                rescan = 0;
2155                inverse = 0;
2156                width = 1;
2157
2158                /* Do no translation at all in control states */
2159                if (vc->vc_state != ESnormal) {
2160                        tc = c;
2161                } else if (vc->vc_utf && !vc->vc_disp_ctrl) {
2162                    /* Combine UTF-8 into Unicode in vc_utf_char.
2163                     * vc_utf_count is the number of continuation bytes still
2164                     * expected to arrive.
2165                     * vc_npar is the number of continuation bytes arrived so
2166                     * far
2167                     */
2168rescan_last_byte:
2169                    if ((c & 0xc0) == 0x80) {
2170                        /* Continuation byte received */
2171                        static const uint32_t utf8_length_changes[] = { 0x0000007f, 0x000007ff, 0x0000ffff, 0x001fffff, 0x03ffffff, 0x7fffffff };
2172                        if (vc->vc_utf_count) {
2173                            vc->vc_utf_char = (vc->vc_utf_char << 6) | (c & 0x3f);
2174                            vc->vc_npar++;
2175                            if (--vc->vc_utf_count) {
2176                                /* Still need some bytes */
2177                                continue;
2178                            }
2179                            /* Got a whole character */
2180                            c = vc->vc_utf_char;
2181                            /* Reject overlong sequences */
2182                            if (c <= utf8_length_changes[vc->vc_npar - 1] ||
2183                                        c > utf8_length_changes[vc->vc_npar])
2184                                c = 0xfffd;
2185                        } else {
2186                            /* Unexpected continuation byte */
2187                            vc->vc_utf_count = 0;
2188                            c = 0xfffd;
2189                        }
2190                    } else {
2191                        /* Single ASCII byte or first byte of a sequence received */
2192                        if (vc->vc_utf_count) {
2193                            /* Continuation byte expected */
2194                            rescan = 1;
2195                            vc->vc_utf_count = 0;
2196                            c = 0xfffd;
2197                        } else if (c > 0x7f) {
2198                            /* First byte of a multibyte sequence received */
2199                            vc->vc_npar = 0;
2200                            if ((c & 0xe0) == 0xc0) {
2201                                vc->vc_utf_count = 1;
2202                                vc->vc_utf_char = (c & 0x1f);
2203                            } else if ((c & 0xf0) == 0xe0) {
2204                                vc->vc_utf_count = 2;
2205                                vc->vc_utf_char = (c & 0x0f);
2206                            } else if ((c & 0xf8) == 0xf0) {
2207                                vc->vc_utf_count = 3;
2208                                vc->vc_utf_char = (c & 0x07);
2209                            } else if ((c & 0xfc) == 0xf8) {
2210                                vc->vc_utf_count = 4;
2211                                vc->vc_utf_char = (c & 0x03);
2212                            } else if ((c & 0xfe) == 0xfc) {
2213                                vc->vc_utf_count = 5;
2214                                vc->vc_utf_char = (c & 0x01);
2215                            } else {
2216                                /* 254 and 255 are invalid */
2217                                c = 0xfffd;
2218                            }
2219                            if (vc->vc_utf_count) {
2220                                /* Still need some bytes */
2221                                continue;
2222                            }
2223                        }
2224                        /* Nothing to do if an ASCII byte was received */
2225                    }
2226                    /* End of UTF-8 decoding. */
2227                    /* c is the received character, or U+FFFD for invalid sequences. */
2228                    /* Replace invalid Unicode code points with U+FFFD too */
2229                    if ((c >= 0xd800 && c <= 0xdfff) || c == 0xfffe || c == 0xffff)
2230                        c = 0xfffd;
2231                    tc = c;
2232                } else {        /* no utf or alternate charset mode */
2233                    tc = vc_translate(vc, c);
2234                }
2235
2236                param.c = tc;
2237                if (atomic_notifier_call_chain(&vt_notifier_list, VT_PREWRITE,
2238                                        &param) == NOTIFY_STOP)
2239                        continue;
2240
2241                /* If the original code was a control character we
2242                 * only allow a glyph to be displayed if the code is
2243                 * not normally used (such as for cursor movement) or
2244                 * if the disp_ctrl mode has been explicitly enabled.
2245                 * Certain characters (as given by the CTRL_ALWAYS
2246                 * bitmap) are always displayed as control characters,
2247                 * as the console would be pretty useless without
2248                 * them; to display an arbitrary font position use the
2249                 * direct-to-font zone in UTF-8 mode.
2250                 */
2251                ok = tc && (c >= 32 ||
2252                            !(vc->vc_disp_ctrl ? (CTRL_ALWAYS >> c) & 1 :
2253                                  vc->vc_utf || ((CTRL_ACTION >> c) & 1)))
2254                        && (c != 127 || vc->vc_disp_ctrl)
2255                        && (c != 128+27);
2256
2257                if (vc->vc_state == ESnormal && ok) {
2258                        if (vc->vc_utf && !vc->vc_disp_ctrl) {
2259                                if (is_double_width(c))
2260                                        width = 2;
2261                        }
2262                        /* Now try to find out how to display it */
2263                        tc = conv_uni_to_pc(vc, tc);
2264                        if (tc & ~charmask) {
2265                                if (tc == -1 || tc == -2) {
2266                                    continue; /* nothing to display */
2267                                }
2268                                /* Glyph not found */
2269                                if ((!(vc->vc_utf && !vc->vc_disp_ctrl) || c < 128) && !(c & ~charmask)) {
2270                                    /* In legacy mode use the glyph we get by a 1:1 mapping.
2271                                       This would make absolutely no sense with Unicode in mind,
2272                                       but do this for ASCII characters since a font may lack
2273                                       Unicode mapping info and we don't want to end up with
2274                                       having question marks only. */
2275                                    tc = c;
2276                                } else {
2277                                    /* Display U+FFFD. If it's not found, display an inverse question mark. */
2278                                    tc = conv_uni_to_pc(vc, 0xfffd);
2279                                    if (tc < 0) {
2280                                        inverse = 1;
2281                                        tc = conv_uni_to_pc(vc, '?');
2282                                        if (tc < 0) tc = '?';
2283                                    }
2284                                }
2285                        }
2286
2287                        if (!inverse) {
2288                                vc_attr = vc->vc_attr;
2289                        } else {
2290                                /* invert vc_attr */
2291                                if (!vc->vc_can_do_color) {
2292                                        vc_attr = (vc->vc_attr) ^ 0x08;
2293                                } else if (vc->vc_hi_font_mask == 0x100) {
2294                                        vc_attr = ((vc->vc_attr) & 0x11) | (((vc->vc_attr) & 0xe0) >> 4) | (((vc->vc_attr) & 0x0e) << 4);
2295                                } else {
2296                                        vc_attr = ((vc->vc_attr) & 0x88) | (((vc->vc_attr) & 0x70) >> 4) | (((vc->vc_attr) & 0x07) << 4);
2297                                }
2298                                FLUSH
2299                        }
2300
2301                        while (1) {
2302                                if (vc->vc_need_wrap || vc->vc_decim)
2303                                        FLUSH
2304                                if (vc->vc_need_wrap) {
2305                                        cr(vc);
2306                                        lf(vc);
2307                                }
2308                                if (vc->vc_decim)
2309                                        insert_char(vc, 1);
2310                                scr_writew(himask ?
2311                                             ((vc_attr << 8) & ~himask) + ((tc & 0x100) ? himask : 0) + (tc & 0xff) :
2312                                             (vc_attr << 8) + tc,
2313                                           (u16 *) vc->vc_pos);
2314                                if (DO_UPDATE(vc) && draw_x < 0) {
2315                                        draw_x = vc->vc_x;
2316                                        draw_from = vc->vc_pos;
2317                                }
2318                                if (vc->vc_x == vc->vc_cols - 1) {
2319                                        vc->vc_need_wrap = vc->vc_decawm;
2320                                        draw_to = vc->vc_pos + 2;
2321                                } else {
2322                                        vc->vc_x++;
2323                                        draw_to = (vc->vc_pos += 2);
2324                                }
2325
2326                                if (!--width) break;
2327
2328                                tc = conv_uni_to_pc(vc, ' '); /* A space is printed in the second column */
2329                                if (tc < 0) tc = ' ';
2330                        }
2331                        notify_write(vc, c);
2332
2333                        if (inverse) {
2334                                FLUSH
2335                        }
2336
2337                        if (rescan) {
2338                                rescan = 0;
2339                                inverse = 0;
2340                                width = 1;
2341                                c = orig;
2342                                goto rescan_last_byte;
2343                        }
2344                        continue;
2345                }
2346                FLUSH
2347                do_con_trol(tty, vc, orig);
2348        }
2349        FLUSH
2350        console_conditional_schedule();
2351        release_console_sem();
2352        notify_update(vc);
2353        return n;
2354#undef FLUSH
2355}
2356
2357/*
2358 * This is the console switching callback.
2359 *
2360 * Doing console switching in a process context allows
2361 * us to do the switches asynchronously (needed when we want
2362 * to switch due to a keyboard interrupt).  Synchronization
2363 * with other console code and prevention of re-entrancy is
2364 * ensured with console_sem.
2365 */
2366static void console_callback(struct work_struct *ignored)
2367{
2368        acquire_console_sem();
2369
2370        if (want_console >= 0) {
2371                if (want_console != fg_console &&
2372                    vc_cons_allocated(want_console)) {
2373                        hide_cursor(vc_cons[fg_console].d);
2374                        change_console(vc_cons[want_console].d);
2375                        /* we only changed when the console had already
2376                           been allocated - a new console is not created
2377                           in an interrupt routine */
2378                }
2379                want_console = -1;
2380        }
2381        if (do_poke_blanked_console) { /* do not unblank for a LED change */
2382                do_poke_blanked_console = 0;
2383                poke_blanked_console();
2384        }
2385        if (scrollback_delta) {
2386                struct vc_data *vc = vc_cons[fg_console].d;
2387                clear_selection();
2388                if (vc->vc_mode == KD_TEXT)
2389                        vc->vc_sw->con_scrolldelta(vc, scrollback_delta);
2390                scrollback_delta = 0;
2391        }
2392        if (blank_timer_expired) {
2393                do_blank_screen(0);
2394                blank_timer_expired = 0;
2395        }
2396        notify_update(vc_cons[fg_console].d);
2397
2398        release_console_sem();
2399}
2400
2401int set_console(int nr)
2402{
2403        struct vc_data *vc = vc_cons[fg_console].d;
2404
2405        if (!vc_cons_allocated(nr) || vt_dont_switch ||
2406                (vc->vt_mode.mode == VT_AUTO && vc->vc_mode == KD_GRAPHICS)) {
2407
2408                /*
2409                 * Console switch will fail in console_callback() or
2410                 * change_console() so there is no point scheduling
2411                 * the callback
2412                 *
2413                 * Existing set_console() users don't check the return
2414                 * value so this shouldn't break anything
2415                 */
2416                return -EINVAL;
2417        }
2418
2419        want_console = nr;
2420        schedule_console_callback();
2421
2422        return 0;
2423}
2424
2425struct tty_driver *console_driver;
2426
2427#ifdef CONFIG_VT_CONSOLE
2428
2429/*
2430 *      Console on virtual terminal
2431 *
2432 * The console must be locked when we get here.
2433 */
2434
2435static void vt_console_print(struct console *co, const char *b, unsigned count)
2436{
2437        struct vc_data *vc = vc_cons[fg_console].d;
2438        unsigned char c;
2439        static DEFINE_SPINLOCK(printing_lock);
2440        const ushort *start;
2441        ushort cnt = 0;
2442        ushort myx;
2443
2444        /* console busy or not yet initialized */
2445        if (!printable)
2446                return;
2447        if (!spin_trylock(&printing_lock))
2448                return;
2449
2450        if (kmsg_redirect && vc_cons_allocated(kmsg_redirect - 1))
2451                vc = vc_cons[kmsg_redirect - 1].d;
2452
2453        /* read `x' only after setting currcons properly (otherwise
2454           the `x' macro will read the x of the foreground console). */
2455        myx = vc->vc_x;
2456
2457        if (!vc_cons_allocated(fg_console)) {
2458                /* impossible */
2459                /* printk("vt_console_print: tty %d not allocated ??\n", currcons+1); */
2460                goto quit;
2461        }
2462
2463        if (vc->vc_mode != KD_TEXT)
2464                goto quit;
2465
2466        /* undraw cursor first */
2467        if (IS_FG(vc))
2468                hide_cursor(vc);
2469
2470        start = (ushort *)vc->vc_pos;
2471
2472        /* Contrived structure to try to emulate original need_wrap behaviour
2473         * Problems caused when we have need_wrap set on '\n' character */
2474        while (count--) {
2475                c = *b++;
2476                if (c == 10 || c == 13 || c == 8 || vc->vc_need_wrap) {
2477                        if (cnt > 0) {
2478                                if (CON_IS_VISIBLE(vc))
2479                                        vc->vc_sw->con_putcs(vc, start, cnt, vc->vc_y, vc->vc_x);
2480                                vc->vc_x += cnt;
2481                                if (vc->vc_need_wrap)
2482                                        vc->vc_x--;
2483                                cnt = 0;
2484                        }
2485                        if (c == 8) {           /* backspace */
2486                                bs(vc);
2487                                start = (ushort *)vc->vc_pos;
2488                                myx = vc->vc_x;
2489                                continue;
2490                        }
2491                        if (c != 13)
2492                                lf(vc);
2493                        cr(vc);
2494                        start = (ushort *)vc->vc_pos;
2495                        myx = vc->vc_x;
2496                        if (c == 10 || c == 13)
2497                                continue;
2498                }
2499                scr_writew((vc->vc_attr << 8) + c, (unsigned short *)vc->vc_pos);
2500                notify_write(vc, c);
2501                cnt++;
2502                if (myx == vc->vc_cols - 1) {
2503                        vc->vc_need_wrap = 1;
2504                        continue;
2505                }
2506                vc->vc_pos += 2;
2507                myx++;
2508        }
2509        if (cnt > 0) {
2510                if (CON_IS_VISIBLE(vc))
2511                        vc->vc_sw->con_putcs(vc, start, cnt, vc->vc_y, vc->vc_x);
2512                vc->vc_x += cnt;
2513                if (vc->vc_x == vc->vc_cols) {
2514                        vc->vc_x--;
2515                        vc->vc_need_wrap = 1;
2516                }
2517        }
2518        set_cursor(vc);
2519        notify_update(vc);
2520
2521quit:
2522        spin_unlock(&printing_lock);
2523}
2524
2525static struct tty_driver *vt_console_device(struct console *c, int *index)
2526{
2527        *index = c->index ? c->index-1 : fg_console;
2528        return console_driver;
2529}
2530
2531static struct console vt_console_driver = {
2532        .name           = "tty",
2533        .write          = vt_console_print,
2534        .device         = vt_console_device,
2535        .unblank        = unblank_screen,
2536        .flags          = CON_PRINTBUFFER,
2537        .index          = -1,
2538};
2539#endif
2540
2541/*
2542 *      Handling of Linux-specific VC ioctls
2543 */
2544
2545/*
2546 * Generally a bit racy with respect to console_sem().
2547 *
2548 * There are some functions which don't need it.
2549 *
2550 * There are some functions which can sleep for arbitrary periods
2551 * (paste_selection) but we don't need the lock there anyway.
2552 *
2553 * set_selection has locking, and definitely needs it
2554 */
2555
2556int tioclinux(struct tty_struct *tty, unsigned long arg)
2557{
2558        char type, data;
2559        char __user *p = (char __user *)arg;
2560        int lines;
2561        int ret;
2562
2563        if (current->signal->tty != tty && !capable(CAP_SYS_ADMIN))
2564                return -EPERM;
2565        if (get_user(type, p))
2566                return -EFAULT;
2567        ret = 0;
2568
2569        lock_kernel();
2570
2571        switch (type)
2572        {
2573                case TIOCL_SETSEL:
2574                        acquire_console_sem();
2575                        ret = set_selection((struct tiocl_selection __user *)(p+1), tty);
2576                        release_console_sem();
2577                        break;
2578                case TIOCL_PASTESEL:
2579                        ret = paste_selection(tty);
2580                        break;
2581                case TIOCL_UNBLANKSCREEN:
2582                        acquire_console_sem();
2583                        unblank_screen();
2584                        release_console_sem();
2585                        break;
2586                case TIOCL_SELLOADLUT:
2587                        ret = sel_loadlut(p);
2588                        break;
2589                case TIOCL_GETSHIFTSTATE:
2590
2591        /*
2592         * Make it possible to react to Shift+Mousebutton.
2593         * Note that 'shift_state' is an undocumented
2594         * kernel-internal variable; programs not closely
2595         * related to the kernel should not use this.
2596         */
2597                        data = shift_state;
2598                        ret = __put_user(data, p);
2599                        break;
2600                case TIOCL_GETMOUSEREPORTING:
2601                        data = mouse_reporting();
2602                        ret = __put_user(data, p);
2603                        break;
2604                case TIOCL_SETVESABLANK:
2605                        ret = set_vesa_blanking(p);
2606                        break;
2607                case TIOCL_GETKMSGREDIRECT:
2608                        data = kmsg_redirect;
2609                        ret = __put_user(data, p);
2610                        break;
2611                case TIOCL_SETKMSGREDIRECT:
2612                        if (!capable(CAP_SYS_ADMIN)) {
2613                                ret = -EPERM;
2614                        } else {
2615                                if (get_user(data, p+1))
2616                                        ret = -EFAULT;
2617                                else
2618                                        kmsg_redirect = data;
2619                        }
2620                        break;
2621                case TIOCL_GETFGCONSOLE:
2622                        ret = fg_console;
2623                        break;
2624                case TIOCL_SCROLLCONSOLE:
2625                        if (get_user(lines, (s32 __user *)(p+4))) {
2626                                ret = -EFAULT;
2627                        } else {
2628                                scrollfront(vc_cons[fg_console].d, lines);
2629                                ret = 0;
2630                        }
2631                        break;
2632                case TIOCL_BLANKSCREEN: /* until explicitly unblanked, not only poked */
2633                        acquire_console_sem();
2634                        ignore_poke = 1;
2635                        do_blank_screen(0);
2636                        release_console_sem();
2637                        break;
2638                case TIOCL_BLANKEDSCREEN:
2639                        ret = console_blanked;
2640                        break;
2641                default:
2642                        ret = -EINVAL;
2643                        break;
2644        }
2645        unlock_kernel();
2646        return ret;
2647}
2648
2649/*
2650 * /dev/ttyN handling
2651 */
2652
2653static int con_write(struct tty_struct *tty, const unsigned char *buf, int count)
2654{
2655        int     retval;
2656
2657        retval = do_con_write(tty, buf, count);
2658        con_flush_chars(tty);
2659
2660        return retval;
2661}
2662
2663static int con_put_char(struct tty_struct *tty, unsigned char ch)
2664{
2665        if (in_interrupt())
2666                return 0;       /* n_r3964 calls put_char() from interrupt context */
2667        return do_con_write(tty, &ch, 1);
2668}
2669
2670static int con_write_room(struct tty_struct *tty)
2671{
2672        if (tty->stopped)
2673                return 0;
2674        return 32768;           /* No limit, really; we're not buffering */
2675}
2676
2677static int con_chars_in_buffer(struct tty_struct *tty)
2678{
2679        return 0;               /* we're not buffering */
2680}
2681
2682/*
2683 * con_throttle and con_unthrottle are only used for
2684 * paste_selection(), which has to stuff in a large number of
2685 * characters...
2686 */
2687static void con_throttle(struct tty_struct *tty)
2688{
2689}
2690
2691static void con_unthrottle(struct tty_struct *tty)
2692{
2693        struct vc_data *vc = tty->driver_data;
2694
2695        wake_up_interruptible(&vc->paste_wait);
2696}
2697
2698/*
2699 * Turn the Scroll-Lock LED on when the tty is stopped
2700 */
2701static void con_stop(struct tty_struct *tty)
2702{
2703        int console_num;
2704        if (!tty)
2705                return;
2706        console_num = tty->index;
2707        if (!vc_cons_allocated(console_num))
2708                return;
2709        set_vc_kbd_led(kbd_table + console_num, VC_SCROLLOCK);
2710        set_leds();
2711}
2712
2713/*
2714 * Turn the Scroll-Lock LED off when the console is started
2715 */
2716static void con_start(struct tty_struct *tty)
2717{
2718        int console_num;
2719        if (!tty)
2720                return;
2721        console_num = tty->index;
2722        if (!vc_cons_allocated(console_num))
2723                return;
2724        clr_vc_kbd_led(kbd_table + console_num, VC_SCROLLOCK);
2725        set_leds();
2726}
2727
2728static void con_flush_chars(struct tty_struct *tty)
2729{
2730        struct vc_data *vc;
2731
2732        if (in_interrupt())     /* from flush_to_ldisc */
2733                return;
2734
2735        /* if we race with con_close(), vt may be null */
2736        acquire_console_sem();
2737        vc = tty->driver_data;
2738        if (vc)
2739                set_cursor(vc);
2740        release_console_sem();
2741}
2742
2743/*
2744 * Allocate the console screen memory.
2745 */
2746static int con_open(struct tty_struct *tty, struct file *filp)
2747{
2748        unsigned int currcons = tty->index;
2749        int ret = 0;
2750
2751        acquire_console_sem();
2752        if (tty->driver_data == NULL) {
2753                ret = vc_allocate(currcons);
2754                if (ret == 0) {
2755                        struct vc_data *vc = vc_cons[currcons].d;
2756
2757                        /* Still being freed */
2758                        if (vc->vc_tty) {
2759                                release_console_sem();
2760                                return -ERESTARTSYS;
2761                        }
2762                        tty->driver_data = vc;
2763                        vc->vc_tty = tty;
2764
2765                        if (!tty->winsize.ws_row && !tty->winsize.ws_col) {
2766                                tty->winsize.ws_row = vc_cons[currcons].d->vc_rows;
2767                                tty->winsize.ws_col = vc_cons[currcons].d->vc_cols;
2768                        }
2769                        if (vc->vc_utf)
2770                                tty->termios->c_iflag |= IUTF8;
2771                        else
2772                                tty->termios->c_iflag &= ~IUTF8;
2773                        release_console_sem();
2774                        return ret;
2775                }
2776        }
2777        release_console_sem();
2778        return ret;
2779}
2780
2781static void con_close(struct tty_struct *tty, struct file *filp)
2782{
2783        /* Nothing to do - we defer to shutdown */
2784}
2785
2786static void con_shutdown(struct tty_struct *tty)
2787{
2788        struct vc_data *vc = tty->driver_data;
2789        BUG_ON(vc == NULL);
2790        acquire_console_sem();
2791        vc->vc_tty = NULL;
2792        release_console_sem();
2793        tty_shutdown(tty);
2794}
2795
2796static int default_italic_color    = 2; // green (ASCII)
2797static int default_underline_color = 3; // cyan (ASCII)
2798module_param_named(italic, default_italic_color, int, S_IRUGO | S_IWUSR);
2799module_param_named(underline, default_underline_color, int, S_IRUGO | S_IWUSR);
2800
2801static void vc_init(struct vc_data *vc, unsigned int rows,
2802                    unsigned int cols, int do_clear)
2803{
2804        int j, k ;
2805
2806        vc->vc_cols = cols;
2807        vc->vc_rows = rows;
2808        vc->vc_size_row = cols << 1;
2809        vc->vc_screenbuf_size = vc->vc_rows * vc->vc_size_row;
2810
2811        set_origin(vc);
2812        vc->vc_pos = vc->vc_origin;
2813        reset_vc(vc);
2814        for (j=k=0; j<16; j++) {
2815                vc->vc_palette[k++] = default_red[j] ;
2816                vc->vc_palette[k++] = default_grn[j] ;
2817                vc->vc_palette[k++] = default_blu[j] ;
2818        }
2819        vc->vc_def_color       = 0x07;   /* white */
2820        vc->vc_ulcolor         = default_underline_color;
2821        vc->vc_itcolor         = default_italic_color;
2822        vc->vc_halfcolor       = 0x08;   /* grey */
2823        init_waitqueue_head(&vc->paste_wait);
2824        reset_terminal(vc, do_clear);
2825}
2826
2827/*
2828 * This routine initializes console interrupts, and does nothing
2829 * else. If you want the screen to clear, call tty_write with
2830 * the appropriate escape-sequence.
2831 */
2832
2833static int __init con_init(void)
2834{
2835        const char *display_desc = NULL;
2836        struct vc_data *vc;
2837        unsigned int currcons = 0, i;
2838
2839        acquire_console_sem();
2840
2841        if (conswitchp)
2842                display_desc = conswitchp->con_startup();
2843        if (!display_desc) {
2844                fg_console = 0;
2845                release_console_sem();
2846                return 0;
2847        }
2848
2849        for (i = 0; i < MAX_NR_CON_DRIVER; i++) {
2850                struct con_driver *con_driver = &registered_con_driver[i];
2851
2852                if (con_driver->con == NULL) {
2853                        con_driver->con = conswitchp;
2854                        con_driver->desc = display_desc;
2855                        con_driver->flag = CON_DRIVER_FLAG_INIT;
2856                        con_driver->first = 0;
2857                        con_driver->last = MAX_NR_CONSOLES - 1;
2858                        break;
2859                }
2860        }
2861
2862        for (i = 0; i < MAX_NR_CONSOLES; i++)
2863                con_driver_map[i] = conswitchp;
2864
2865        if (blankinterval) {
2866                blank_state = blank_normal_wait;
2867                mod_timer(&console_timer, jiffies + (blankinterval * HZ));
2868        }
2869
2870        for (currcons = 0; currcons < MIN_NR_CONSOLES; currcons++) {
2871                vc_cons[currcons].d = vc = kzalloc(sizeof(struct vc_data), GFP_NOWAIT);
2872                INIT_WORK(&vc_cons[currcons].SAK_work, vc_SAK);
2873                visual_init(vc, currcons, 1);
2874                vc->vc_screenbuf = kzalloc(vc->vc_screenbuf_size, GFP_NOWAIT);
2875                vc_init(vc, vc->vc_rows, vc->vc_cols,
2876                        currcons || !vc->vc_sw->con_save_screen);
2877        }
2878        currcons = fg_console = 0;
2879        master_display_fg = vc = vc_cons[currcons].d;
2880        set_origin(vc);
2881        save_screen(vc);
2882        gotoxy(vc, vc->vc_x, vc->vc_y);
2883        csi_J(vc, 0);
2884        update_screen(vc);
2885        printk("Console: %s %s %dx%d",
2886                vc->vc_can_do_color ? "colour" : "mono",
2887                display_desc, vc->vc_cols, vc->vc_rows);
2888        printable = 1;
2889        printk("\n");
2890
2891        release_console_sem();
2892
2893#ifdef CONFIG_VT_CONSOLE
2894        register_console(&vt_console_driver);
2895#endif
2896        return 0;
2897}
2898console_initcall(con_init);
2899
2900static const struct tty_operations con_ops = {
2901        .open = con_open,
2902        .close = con_close,
2903        .write = con_write,
2904        .write_room = con_write_room,
2905        .put_char = con_put_char,
2906        .flush_chars = con_flush_chars,
2907        .chars_in_buffer = con_chars_in_buffer,
2908        .ioctl = vt_ioctl,
2909#ifdef CONFIG_COMPAT
2910        .compat_ioctl = vt_compat_ioctl,
2911#endif
2912        .stop = con_stop,
2913        .start = con_start,
2914        .throttle = con_throttle,
2915        .unthrottle = con_unthrottle,
2916        .resize = vt_resize,
2917        .shutdown = con_shutdown
2918};
2919
2920static struct cdev vc0_cdev;
2921
2922int __init vty_init(const struct file_operations *console_fops)
2923{
2924        cdev_init(&vc0_cdev, console_fops);
2925        if (cdev_add(&vc0_cdev, MKDEV(TTY_MAJOR, 0), 1) ||
2926            register_chrdev_region(MKDEV(TTY_MAJOR, 0), 1, "/dev/vc/0") < 0)
2927                panic("Couldn't register /dev/tty0 driver\n");
2928        device_create(tty_class, NULL, MKDEV(TTY_MAJOR, 0), NULL, "tty0");
2929
2930        vcs_init();
2931
2932        console_driver = alloc_tty_driver(MAX_NR_CONSOLES);
2933        if (!console_driver)
2934                panic("Couldn't allocate console driver\n");
2935        console_driver->owner = THIS_MODULE;
2936        console_driver->name = "tty";
2937        console_driver->name_base = 1;
2938        console_driver->major = TTY_MAJOR;
2939        console_driver->minor_start = 1;
2940        console_driver->type = TTY_DRIVER_TYPE_CONSOLE;
2941        console_driver->init_termios = tty_std_termios;
2942        if (default_utf8)
2943                console_driver->init_termios.c_iflag |= IUTF8;
2944        console_driver->flags = TTY_DRIVER_REAL_RAW | TTY_DRIVER_RESET_TERMIOS;
2945        tty_set_operations(console_driver, &con_ops);
2946        if (tty_register_driver(console_driver))
2947                panic("Couldn't register console driver\n");
2948        kbd_init();
2949        console_map_init();
2950#ifdef CONFIG_MDA_CONSOLE
2951        mda_console_init();
2952#endif
2953        return 0;
2954}
2955
2956#ifndef VT_SINGLE_DRIVER
2957
2958static struct class *vtconsole_class;
2959
2960static int bind_con_driver(const struct consw *csw, int first, int last,
2961                           int deflt)
2962{
2963        struct module *owner = csw->owner;
2964        const char *desc = NULL;
2965        struct con_driver *con_driver;
2966        int i, j = -1, k = -1, retval = -ENODEV;
2967
2968        if (!try_module_get(owner))
2969                return -ENODEV;
2970
2971        acquire_console_sem();
2972
2973        /* check if driver is registered */
2974        for (i = 0; i < MAX_NR_CON_DRIVER; i++) {
2975                con_driver = &registered_con_driver[i];
2976
2977                if (con_driver->con == csw) {
2978                        desc = con_driver->desc;
2979                        retval = 0;
2980                        break;
2981                }
2982        }
2983
2984        if (retval)
2985                goto err;
2986
2987        if (!(con_driver->flag & CON_DRIVER_FLAG_INIT)) {
2988                csw->con_startup();
2989                con_driver->flag |= CON_DRIVER_FLAG_INIT;
2990        }
2991
2992        if (deflt) {
2993                if (conswitchp)
2994                        module_put(conswitchp->owner);
2995
2996                __module_get(owner);
2997                conswitchp = csw;
2998        }
2999
3000        first = max(first, con_driver->first);
3001        last = min(last, con_driver->last);
3002
3003        for (i = first; i <= last; i++) {
3004                int old_was_color;
3005                struct vc_data *vc = vc_cons[i].d;
3006
3007                if (con_driver_map[i])
3008                        module_put(con_driver_map[i]->owner);
3009                __module_get(owner);
3010                con_driver_map[i] = csw;
3011
3012                if (!vc || !vc->vc_sw)
3013                        continue;
3014
3015                j = i;
3016
3017                if (CON_IS_VISIBLE(vc)) {
3018                        k = i;
3019                        save_screen(vc);
3020                }
3021
3022                old_was_color = vc->vc_can_do_color;
3023                vc->vc_sw->con_deinit(vc);
3024                vc->vc_origin = (unsigned long)vc->vc_screenbuf;
3025                visual_init(vc, i, 0);
3026                set_origin(vc);
3027                update_attr(vc);
3028
3029                /* If the console changed between mono <-> color, then
3030                 * the attributes in the screenbuf will be wrong.  The
3031                 * following resets all attributes to something sane.
3032                 */
3033                if (old_was_color != vc->vc_can_do_color)
3034                        clear_buffer_attributes(vc);
3035        }
3036
3037        printk("Console: switching ");
3038        if (!deflt)
3039                printk("consoles %d-%d ", first+1, last+1);
3040        if (j >= 0) {
3041                struct vc_data *vc = vc_cons[j].d;
3042
3043                printk("to %s %s %dx%d\n",
3044                       vc->vc_can_do_color ? "colour" : "mono",
3045                       desc, vc->vc_cols, vc->vc_rows);
3046
3047                if (k >= 0) {
3048                        vc = vc_cons[k].d;
3049                        update_screen(vc);
3050                }
3051        } else
3052                printk("to %s\n", desc);
3053
3054        retval = 0;
3055err:
3056        release_console_sem();
3057        module_put(owner);
3058        return retval;
3059};
3060
3061#ifdef CONFIG_VT_HW_CONSOLE_BINDING
3062static int con_is_graphics(const struct consw *csw, int first, int last)
3063{
3064        int i, retval = 0;
3065
3066        for (i = first; i <= last; i++) {
3067                struct vc_data *vc = vc_cons[i].d;
3068
3069                if (vc && vc->vc_mode == KD_GRAPHICS) {
3070                        retval = 1;
3071                        break;
3072                }
3073        }
3074
3075        return retval;
3076}
3077
3078/**
3079 * unbind_con_driver - unbind a console driver
3080 * @csw: pointer to console driver to unregister
3081 * @first: first in range of consoles that @csw should be unbound from
3082 * @last: last in range of consoles that @csw should be unbound from
3083 * @deflt: should next bound console driver be default after @csw is unbound?
3084 *
3085 * To unbind a driver from all possible consoles, pass 0 as @first and
3086 * %MAX_NR_CONSOLES as @last.
3087 *
3088 * @deflt controls whether the console that ends up replacing @csw should be
3089 * the default console.
3090 *
3091 * RETURNS:
3092 * -ENODEV if @csw isn't a registered console driver or can't be unregistered
3093 * or 0 on success.
3094 */
3095int unbind_con_driver(const struct consw *csw, int first, int last, int deflt)
3096{
3097        struct module *owner = csw->owner;
3098        const struct consw *defcsw = NULL;
3099        struct con_driver *con_driver = NULL, *con_back = NULL;
3100        int i, retval = -ENODEV;
3101
3102        if (!try_module_get(owner))
3103                return -ENODEV;
3104
3105        acquire_console_sem();
3106
3107        /* check if driver is registered and if it is unbindable */
3108        for (i = 0; i < MAX_NR_CON_DRIVER; i++) {
3109                con_driver = &registered_con_driver[i];
3110
3111                if (con_driver->con == csw &&
3112                    con_driver->flag & CON_DRIVER_FLAG_MODULE) {
3113                        retval = 0;
3114                        break;
3115                }
3116        }
3117
3118        if (retval) {
3119                release_console_sem();
3120                goto err;
3121        }
3122
3123        retval = -ENODEV;
3124
3125        /* check if backup driver exists */
3126        for (i = 0; i < MAX_NR_CON_DRIVER; i++) {
3127                con_back = &registered_con_driver[i];
3128
3129                if (con_back->con &&
3130                    !(con_back->flag & CON_DRIVER_FLAG_MODULE)) {
3131                        defcsw = con_back->con;
3132                        retval = 0;
3133                        break;
3134                }
3135        }
3136
3137        if (retval) {
3138                release_console_sem();
3139                goto err;
3140        }
3141
3142        if (!con_is_bound(csw)) {
3143                release_console_sem();
3144                goto err;
3145        }
3146
3147        first = max(first, con_driver->first);
3148        last = min(last, con_driver->last);
3149
3150        for (i = first; i <= last; i++) {
3151                if (con_driver_map[i] == csw) {
3152                        module_put(csw->owner);
3153                        con_driver_map[i] = NULL;
3154                }
3155        }
3156
3157        if (!con_is_bound(defcsw)) {
3158                const struct consw *defconsw = conswitchp;
3159
3160                defcsw->con_startup();
3161                con_back->flag |= CON_DRIVER_FLAG_INIT;
3162                /*
3163                 * vgacon may change the default driver to point
3164                 * to dummycon, we restore it here...
3165                 */
3166                conswitchp = defconsw;
3167        }
3168
3169        if (!con_is_bound(csw))
3170                con_driver->flag &= ~CON_DRIVER_FLAG_INIT;
3171
3172        release_console_sem();
3173        /* ignore return value, binding should not fail */
3174        bind_con_driver(defcsw, first, last, deflt);
3175err:
3176        module_put(owner);
3177        return retval;
3178
3179}
3180EXPORT_SYMBOL(unbind_con_driver);
3181
3182static int vt_bind(struct con_driver *con)
3183{
3184        const struct consw *defcsw = NULL, *csw = NULL;
3185        int i, more = 1, first = -1, last = -1, deflt = 0;
3186
3187        if (!con->con || !(con->flag & CON_DRIVER_FLAG_MODULE) ||
3188            con_is_graphics(con->con, con->first, con->last))
3189                goto err;
3190
3191        csw = con->con;
3192
3193        for (i = 0; i < MAX_NR_CON_DRIVER; i++) {
3194                struct con_driver *con = &registered_con_driver[i];
3195
3196                if (con->con && !(con->flag & CON_DRIVER_FLAG_MODULE)) {
3197                        defcsw = con->con;
3198                        break;
3199                }
3200        }
3201
3202        if (!defcsw)
3203                goto err;
3204
3205        while (more) {
3206                more = 0;
3207
3208                for (i = con->first; i <= con->last; i++) {
3209                        if (con_driver_map[i] == defcsw) {
3210                                if (first == -1)
3211                                        first = i;
3212                                last = i;
3213                                more = 1;
3214                        } else if (first != -1)
3215                                break;
3216                }
3217
3218                if (first == 0 && last == MAX_NR_CONSOLES -1)
3219                        deflt = 1;
3220
3221                if (first != -1)
3222                        bind_con_driver(csw, first, last, deflt);
3223
3224                first = -1;
3225                last = -1;
3226                deflt = 0;
3227        }
3228
3229err:
3230        return 0;
3231}
3232
3233static int vt_unbind(struct con_driver *con)
3234{
3235        const struct consw *csw = NULL;
3236        int i, more = 1, first = -1, last = -1, deflt = 0;
3237
3238        if (!con->con || !(con->flag & CON_DRIVER_FLAG_MODULE) ||
3239            con_is_graphics(con->con, con->first, con->last))
3240                goto err;
3241
3242        csw = con->con;
3243
3244        while (more) {
3245                more = 0;
3246
3247                for (i = con->first; i <= con->last; i++) {
3248                        if (con_driver_map[i] == csw) {
3249                                if (first == -1)
3250                                        first = i;
3251                                last = i;
3252                                more = 1;
3253                        } else if (first != -1)
3254                                break;
3255                }
3256
3257                if (first == 0 && last == MAX_NR_CONSOLES -1)
3258                        deflt = 1;
3259
3260                if (first != -1)
3261                        unbind_con_driver(csw, first, last, deflt);
3262
3263                first = -1;
3264                last = -1;
3265                deflt = 0;
3266        }
3267
3268err:
3269        return 0;
3270}
3271#else
3272static inline int vt_bind(struct con_driver *con)
3273{
3274        return 0;
3275}
3276static inline int vt_unbind(struct con_driver *con)
3277{
3278        return 0;
3279}
3280#endif /* CONFIG_VT_HW_CONSOLE_BINDING */
3281
3282static ssize_t store_bind(struct device *dev, struct device_attribute *attr,
3283                          const char *buf, size_t count)
3284{
3285        struct con_driver *con = dev_get_drvdata(dev);
3286        int bind = simple_strtoul(buf, NULL, 0);
3287
3288        if (bind)
3289                vt_bind(con);
3290        else
3291                vt_unbind(con);
3292
3293        return count;
3294}
3295
3296static ssize_t show_bind(struct device *dev, struct device_attribute *attr,
3297                         char *buf)
3298{
3299        struct con_driver *con = dev_get_drvdata(dev);
3300        int bind = con_is_bound(con->con);
3301
3302        return snprintf(buf, PAGE_SIZE, "%i\n", bind);
3303}
3304
3305static ssize_t show_name(struct device *dev, struct device_attribute *attr,
3306                         char *buf)
3307{
3308        struct con_driver *con = dev_get_drvdata(dev);
3309
3310        return snprintf(buf, PAGE_SIZE, "%s %s\n",
3311                        (con->flag & CON_DRIVER_FLAG_MODULE) ? "(M)" : "(S)",
3312                         con->desc);
3313
3314}
3315
3316static struct device_attribute device_attrs[] = {
3317        __ATTR(bind, S_IRUGO|S_IWUSR, show_bind, store_bind),
3318        __ATTR(name, S_IRUGO, show_name, NULL),
3319};
3320
3321static int vtconsole_init_device(struct con_driver *con)
3322{
3323        int i;
3324        int error = 0;
3325
3326        con->flag |= CON_DRIVER_FLAG_ATTR;
3327        dev_set_drvdata(con->dev, con);
3328        for (i = 0; i < ARRAY_SIZE(device_attrs); i++) {
3329                error = device_create_file(con->dev, &device_attrs[i]);
3330                if (error)
3331                        break;
3332        }
3333
3334        if (error) {
3335                while (--i >= 0)
3336                        device_remove_file(con->dev, &device_attrs[i]);
3337                con->flag &= ~CON_DRIVER_FLAG_ATTR;
3338        }
3339
3340        return error;
3341}
3342
3343static void vtconsole_deinit_device(struct con_driver *con)
3344{
3345        int i;
3346
3347        if (con->flag & CON_DRIVER_FLAG_ATTR) {
3348                for (i = 0; i < ARRAY_SIZE(device_attrs); i++)
3349                        device_remove_file(con->dev, &device_attrs[i]);
3350                con->flag &= ~CON_DRIVER_FLAG_ATTR;
3351        }
3352}
3353
3354/**
3355 * con_is_bound - checks if driver is bound to the console
3356 * @csw: console driver
3357 *
3358 * RETURNS: zero if unbound, nonzero if bound
3359 *
3360 * Drivers can call this and if zero, they should release
3361 * all resources allocated on con_startup()
3362 */
3363int con_is_bound(const struct consw *csw)
3364{
3365        int i, bound = 0;
3366
3367        for (i = 0; i < MAX_NR_CONSOLES; i++) {
3368                if (con_driver_map[i] == csw) {
3369                        bound = 1;
3370                        break;
3371                }
3372        }
3373
3374        return bound;
3375}
3376EXPORT_SYMBOL(con_is_bound);
3377
3378/**
3379 * register_con_driver - register console driver to console layer
3380 * @csw: console driver
3381 * @first: the first console to take over, minimum value is 0
3382 * @last: the last console to take over, maximum value is MAX_NR_CONSOLES -1
3383 *
3384 * DESCRIPTION: This function registers a console driver which can later
3385 * bind to a range of consoles specified by @first and @last. It will
3386 * also initialize the console driver by calling con_startup().
3387 */
3388int register_con_driver(const struct consw *csw, int first, int last)
3389{
3390        struct module *owner = csw->owner;
3391        struct con_driver *con_driver;
3392        const char *desc;
3393        int i, retval = 0;
3394
3395        if (!try_module_get(owner))
3396                return -ENODEV;
3397
3398        acquire_console_sem();
3399
3400        for (i = 0; i < MAX_NR_CON_DRIVER; i++) {
3401                con_driver = &registered_con_driver[i];
3402
3403                /* already registered */
3404                if (con_driver->con == csw)
3405                        retval = -EINVAL;
3406        }
3407
3408        if (retval)
3409                goto err;
3410
3411        desc = csw->con_startup();
3412
3413        if (!desc)
3414                goto err;
3415
3416        retval = -EINVAL;
3417
3418        for (i = 0; i < MAX_NR_CON_DRIVER; i++) {
3419                con_driver = &registered_con_driver[i];
3420
3421                if (con_driver->con == NULL) {
3422                        con_driver->con = csw;
3423                        con_driver->desc = desc;
3424                        con_driver->node = i;
3425                        con_driver->flag = CON_DRIVER_FLAG_MODULE |
3426                                           CON_DRIVER_FLAG_INIT;
3427                        con_driver->first = first;
3428                        con_driver->last = last;
3429                        retval = 0;
3430                        break;
3431                }
3432        }
3433
3434        if (retval)
3435                goto err;
3436
3437        con_driver->dev = device_create(vtconsole_class, NULL,
3438                                                MKDEV(0, con_driver->node),
3439                                                NULL, "vtcon%i",
3440                                                con_driver->node);
3441
3442        if (IS_ERR(con_driver->dev)) {
3443                printk(KERN_WARNING "Unable to create device for %s; "
3444                       "errno = %ld\n", con_driver->desc,
3445                       PTR_ERR(con_driver->dev));
3446                con_driver->dev = NULL;
3447        } else {
3448                vtconsole_init_device(con_driver);
3449        }
3450
3451err:
3452        release_console_sem();
3453        module_put(owner);
3454        return retval;
3455}
3456EXPORT_SYMBOL(register_con_driver);
3457
3458/**
3459 * unregister_con_driver - unregister console driver from console layer
3460 * @csw: console driver
3461 *
3462 * DESCRIPTION: All drivers that registers to the console layer must
3463 * call this function upon exit, or if the console driver is in a state
3464 * where it won't be able to handle console services, such as the
3465 * framebuffer console without loaded framebuffer drivers.
3466 *
3467 * The driver must unbind first prior to unregistration.
3468 */
3469int unregister_con_driver(const struct consw *csw)
3470{
3471        int i, retval = -ENODEV;
3472
3473        acquire_console_sem();
3474
3475        /* cannot unregister a bound driver */
3476        if (con_is_bound(csw))
3477                goto err;
3478
3479        for (i = 0; i < MAX_NR_CON_DRIVER; i++) {
3480                struct con_driver *con_driver = &registered_con_driver[i];
3481
3482                if (con_driver->con == csw &&
3483                    con_driver->flag & CON_DRIVER_FLAG_MODULE) {
3484                        vtconsole_deinit_device(con_driver);
3485                        device_destroy(vtconsole_class,
3486                                       MKDEV(0, con_driver->node));
3487                        con_driver->con = NULL;
3488                        con_driver->desc = NULL;
3489                        con_driver->dev = NULL;
3490                        con_driver->node = 0;
3491                        con_driver->flag = 0;
3492                        con_driver->first = 0;
3493                        con_driver->last = 0;
3494                        retval = 0;
3495                        break;
3496                }
3497        }
3498err:
3499        release_console_sem();
3500        return retval;
3501}
3502EXPORT_SYMBOL(unregister_con_driver);
3503
3504/*
3505 *      If we support more console drivers, this function is used
3506 *      when a driver wants to take over some existing consoles
3507 *      and become default driver for newly opened ones.
3508 *
3509 *      take_over_console is basically a register followed by unbind
3510 */
3511int take_over_console(const struct consw *csw, int first, int last, int deflt)
3512{
3513        int err;
3514
3515        err = register_con_driver(csw, first, last);
3516
3517        if (!err)
3518                bind_con_driver(csw, first, last, deflt);
3519
3520        return err;
3521}
3522
3523/*
3524 * give_up_console is a wrapper to unregister_con_driver. It will only
3525 * work if driver is fully unbound.
3526 */
3527void give_up_console(const struct consw *csw)
3528{
3529        unregister_con_driver(csw);
3530}
3531
3532static int __init vtconsole_class_init(void)
3533{
3534        int i;
3535
3536        vtconsole_class = class_create(THIS_MODULE, "vtconsole");
3537        if (IS_ERR(vtconsole_class)) {
3538                printk(KERN_WARNING "Unable to create vt console class; "
3539                       "errno = %ld\n", PTR_ERR(vtconsole_class));
3540                vtconsole_class = NULL;
3541        }
3542
3543        /* Add system drivers to sysfs */
3544        for (i = 0; i < MAX_NR_CON_DRIVER; i++) {
3545                struct con_driver *con = &registered_con_driver[i];
3546
3547                if (con->con && !con->dev) {
3548                        con->dev = device_create(vtconsole_class, NULL,
3549                                                         MKDEV(0, con->node),
3550                                                         NULL, "vtcon%i",
3551                                                         con->node);
3552
3553                        if (IS_ERR(con->dev)) {
3554                                printk(KERN_WARNING "Unable to create "
3555                                       "device for %s; errno = %ld\n",
3556                                       con->desc, PTR_ERR(con->dev));
3557                                con->dev = NULL;
3558                        } else {
3559                                vtconsole_init_device(con);
3560                        }
3561                }
3562        }
3563
3564        return 0;
3565}
3566postcore_initcall(vtconsole_class_init);
3567
3568#endif
3569
3570/*
3571 *      Screen blanking
3572 */
3573
3574static int set_vesa_blanking(char __user *p)
3575{
3576        unsigned int mode;
3577
3578        if (get_user(mode, p + 1))
3579                return -EFAULT;
3580
3581        vesa_blank_mode = (mode < 4) ? mode : 0;
3582        return 0;
3583}
3584
3585void do_blank_screen(int entering_gfx)
3586{
3587        struct vc_data *vc = vc_cons[fg_console].d;
3588        int i;
3589
3590        WARN_CONSOLE_UNLOCKED();
3591
3592        if (console_blanked) {
3593                if (blank_state == blank_vesa_wait) {
3594                        blank_state = blank_off;
3595                        vc->vc_sw->con_blank(vc, vesa_blank_mode + 1, 0);
3596                }
3597                return;
3598        }
3599
3600        /* entering graphics mode? */
3601        if (entering_gfx) {
3602                hide_cursor(vc);
3603                save_screen(vc);
3604                vc->vc_sw->con_blank(vc, -1, 1);
3605                console_blanked = fg_console + 1;
3606                blank_state = blank_off;
3607                set_origin(vc);
3608                return;
3609        }
3610
3611        if (blank_state != blank_normal_wait)
3612                return;
3613        blank_state = blank_off;
3614
3615        /* don't blank graphics */
3616        if (vc->vc_mode != KD_TEXT) {
3617                console_blanked = fg_console + 1;
3618                return;
3619        }
3620
3621        hide_cursor(vc);
3622        del_timer_sync(&console_timer);
3623        blank_timer_expired = 0;
3624
3625        save_screen(vc);
3626        /* In case we need to reset origin, blanking hook returns 1 */
3627        i = vc->vc_sw->con_blank(vc, vesa_off_interval ? 1 : (vesa_blank_mode + 1), 0);
3628        console_blanked = fg_console + 1;
3629        if (i)
3630                set_origin(vc);
3631
3632        if (console_blank_hook && console_blank_hook(1))
3633                return;
3634
3635        if (vesa_off_interval && vesa_blank_mode) {
3636                blank_state = blank_vesa_wait;
3637                mod_timer(&console_timer, jiffies + vesa_off_interval);
3638        }
3639        vt_event_post(VT_EVENT_BLANK, vc->vc_num, vc->vc_num);
3640}
3641EXPORT_SYMBOL(do_blank_screen);
3642
3643/*
3644 * Called by timer as well as from vt_console_driver
3645 */
3646void do_unblank_screen(int leaving_gfx)
3647{
3648        struct vc_data *vc;
3649
3650        /* This should now always be called from a "sane" (read: can schedule)
3651         * context for the sake of the low level drivers, except in the special
3652         * case of oops_in_progress
3653         */
3654        if (!oops_in_progress)
3655                might_sleep();
3656
3657        WARN_CONSOLE_UNLOCKED();
3658
3659        ignore_poke = 0;
3660        if (!console_blanked)
3661                return;
3662        if (!vc_cons_allocated(fg_console)) {
3663                /* impossible */
3664                printk("unblank_screen: tty %d not allocated ??\n", fg_console+1);
3665                return;
3666        }
3667        vc = vc_cons[fg_console].d;
3668        if (vc->vc_mode != KD_TEXT)
3669                return; /* but leave console_blanked != 0 */
3670
3671        if (blankinterval) {
3672                mod_timer(&console_timer, jiffies + (blankinterval * HZ));
3673                blank_state = blank_normal_wait;
3674        }
3675
3676        console_blanked = 0;
3677        if (vc->vc_sw->con_blank(vc, 0, leaving_gfx))
3678                /* Low-level driver cannot restore -> do it ourselves */
3679                update_screen(vc);
3680        if (console_blank_hook)
3681                console_blank_hook(0);
3682        set_palette(vc);
3683        set_cursor(vc);
3684        vt_event_post(VT_EVENT_UNBLANK, vc->vc_num, vc->vc_num);
3685}
3686EXPORT_SYMBOL(do_unblank_screen);
3687
3688/*
3689 * This is called by the outside world to cause a forced unblank, mostly for
3690 * oopses. Currently, I just call do_unblank_screen(0), but we could eventually
3691 * call it with 1 as an argument and so force a mode restore... that may kill
3692 * X or at least garbage the screen but would also make the Oops visible...
3693 */
3694void unblank_screen(void)
3695{
3696        do_unblank_screen(0);
3697}
3698
3699/*
3700 * We defer the timer blanking to work queue so it can take the console mutex
3701 * (console operations can still happen at irq time, but only from printk which
3702 * has the console mutex. Not perfect yet, but better than no locking
3703 */
3704static void blank_screen_t(unsigned long dummy)
3705{
3706        if (unlikely(!keventd_up())) {
3707                mod_timer(&console_timer, jiffies + (blankinterval * HZ));
3708                return;
3709        }
3710        blank_timer_expired = 1;
3711        schedule_work(&console_work);
3712}
3713
3714void poke_blanked_console(void)
3715{
3716        WARN_CONSOLE_UNLOCKED();
3717
3718        /* Add this so we quickly catch whoever might call us in a non
3719         * safe context. Nowadays, unblank_screen() isn't to be called in
3720         * atomic contexts and is allowed to schedule (with the special case
3721         * of oops_in_progress, but that isn't of any concern for this
3722         * function. --BenH.
3723         */
3724        might_sleep();
3725
3726        /* This isn't perfectly race free, but a race here would be mostly harmless,
3727         * at worse, we'll do a spurrious blank and it's unlikely
3728         */
3729        del_timer(&console_timer);
3730        blank_timer_expired = 0;
3731
3732        if (ignore_poke || !vc_cons[fg_console].d || vc_cons[fg_console].d->vc_mode == KD_GRAPHICS)
3733                return;
3734        if (console_blanked)
3735                unblank_screen();
3736        else if (blankinterval) {
3737                mod_timer(&console_timer, jiffies + (blankinterval * HZ));
3738                blank_state = blank_normal_wait;
3739        }
3740}
3741
3742/*
3743 *      Palettes
3744 */
3745
3746static void set_palette(struct vc_data *vc)
3747{
3748        WARN_CONSOLE_UNLOCKED();
3749
3750        if (vc->vc_mode != KD_GRAPHICS)
3751                vc->vc_sw->con_set_palette(vc, color_table);
3752}
3753
3754static int set_get_cmap(unsigned char __user *arg, int set)
3755{
3756    int i, j, k;
3757
3758    WARN_CONSOLE_UNLOCKED();
3759
3760    for (i = 0; i < 16; i++)
3761        if (set) {
3762            get_user(default_red[i], arg++);
3763            get_user(default_grn[i], arg++);
3764            get_user(default_blu[i], arg++);
3765        } else {
3766            put_user(default_red[i], arg++);
3767            put_user(default_grn[i], arg++);
3768            put_user(default_blu[i], arg++);
3769        }
3770    if (set) {
3771        for (i = 0; i < MAX_NR_CONSOLES; i++)
3772            if (vc_cons_allocated(i)) {
3773                for (j = k = 0; j < 16; j++) {
3774                    vc_cons[i].d->vc_palette[k++] = default_red[j];
3775                    vc_cons[i].d->vc_palette[k++] = default_grn[j];
3776                    vc_cons[i].d->vc_palette[k++] = default_blu[j];
3777                }
3778                set_palette(vc_cons[i].d);
3779            }
3780    }
3781    return 0;
3782}
3783
3784/*
3785 * Load palette into the DAC registers. arg points to a colour
3786 * map, 3 bytes per colour, 16 colours, range from 0 to 255.
3787 */
3788
3789int con_set_cmap(unsigned char __user *arg)
3790{
3791        int rc;
3792
3793        acquire_console_sem();
3794        rc = set_get_cmap (arg,1);
3795        release_console_sem();
3796
3797        return rc;
3798}
3799
3800int con_get_cmap(unsigned char __user *arg)
3801{
3802        int rc;
3803
3804        acquire_console_sem();
3805        rc = set_get_cmap (arg,0);
3806        release_console_sem();
3807
3808        return rc;
3809}
3810
3811void reset_palette(struct vc_data *vc)
3812{
3813        int j, k;
3814        for (j=k=0; j<16; j++) {
3815                vc->vc_palette[k++] = default_red[j];
3816                vc->vc_palette[k++] = default_grn[j];
3817                vc->vc_palette[k++] = default_blu[j];
3818        }
3819        set_palette(vc);
3820}
3821
3822/*
3823 *  Font switching
3824 *
3825 *  Currently we only support fonts up to 32 pixels wide, at a maximum height
3826 *  of 32 pixels. Userspace fontdata is stored with 32 bytes (shorts/ints, 
3827 *  depending on width) reserved for each character which is kinda wasty, but 
3828 *  this is done in order to maintain compatibility with the EGA/VGA fonts. It 
3829 *  is upto the actual low-level console-driver convert data into its favorite
3830 *  format (maybe we should add a `fontoffset' field to the `display'
3831 *  structure so we won't have to convert the fontdata all the time.
3832 *  /Jes
3833 */
3834
3835#define max_font_size 65536
3836
3837static int con_font_get(struct vc_data *vc, struct console_font_op *op)
3838{
3839        struct console_font font;
3840        int rc = -EINVAL;
3841        int c;
3842
3843        if (vc->vc_mode != KD_TEXT)
3844                return -EINVAL;
3845
3846        if (op->data) {
3847                font.data = kmalloc(max_font_size, GFP_KERNEL);
3848                if (!font.data)
3849                        return -ENOMEM;
3850        } else
3851                font.data = NULL;
3852
3853        acquire_console_sem();
3854        if (vc->vc_sw->con_font_get)
3855                rc = vc->vc_sw->con_font_get(vc, &font);
3856        else
3857                rc = -ENOSYS;
3858        release_console_sem();
3859
3860        if (rc)
3861                goto out;
3862
3863        c = (font.width+7)/8 * 32 * font.charcount;
3864
3865        if (op->data && font.charcount > op->charcount)
3866                rc = -ENOSPC;
3867        if (!(op->flags & KD_FONT_FLAG_OLD)) {
3868                if (font.width > op->width || font.height > op->height) 
3869                        rc = -ENOSPC;
3870        } else {
3871                if (font.width != 8)
3872                        rc = -EIO;
3873                else if ((op->height && font.height > op->height) ||
3874                         font.height > 32)
3875                        rc = -ENOSPC;
3876        }
3877        if (rc)
3878                goto out;
3879
3880        op->height = font.height;
3881        op->width = font.width;
3882        op->charcount = font.charcount;
3883
3884        if (op->data && copy_to_user(op->data, font.data, c))
3885                rc = -EFAULT;
3886
3887out:
3888        kfree(font.data);
3889        return rc;
3890}
3891
3892static int con_font_set(struct vc_data *vc, struct console_font_op *op)
3893{
3894        struct console_font font;
3895        int rc = -EINVAL;
3896        int size;
3897
3898        if (vc->vc_mode != KD_TEXT)
3899                return -EINVAL;
3900        if (!op->data)
3901                return -EINVAL;
3902        if (op->charcount > 512)
3903                return -EINVAL;
3904        if (!op->height) {              /* Need to guess font height [compat] */
3905                int h, i;
3906                u8 __user *charmap = op->data;
3907                u8 tmp;
3908                
3909                /* If from KDFONTOP ioctl, don't allow things which can be done in userland,
3910                   so that we can get rid of this soon */
3911                if (!(op->flags & KD_FONT_FLAG_OLD))
3912                        return -EINVAL;
3913                for (h = 32; h > 0; h--)
3914                        for (i = 0; i < op->charcount; i++) {
3915                                if (get_user(tmp, &charmap[32*i+h-1]))
3916                                        return -EFAULT;
3917                                if (tmp)
3918                                        goto nonzero;
3919                        }
3920                return -EINVAL;
3921        nonzero:
3922                op->height = h;
3923        }
3924        if (op->width <= 0 || op->width > 32 || op->height > 32)
3925                return -EINVAL;
3926        size = (op->width+7)/8 * 32 * op->charcount;
3927        if (size > max_font_size)
3928                return -ENOSPC;
3929        font.charcount = op->charcount;
3930        font.height = op->height;
3931        font.width = op->width;
3932        font.data = kmalloc(size, GFP_KERNEL);
3933        if (!font.data)
3934                return -ENOMEM;
3935        if (copy_from_user(font.data, op->data, size)) {
3936                kfree(font.data);
3937                return -EFAULT;
3938        }
3939        acquire_console_sem();
3940        if (vc->vc_sw->con_font_set)
3941                rc = vc->vc_sw->con_font_set(vc, &font, op->flags);
3942        else
3943                rc = -ENOSYS;
3944        release_console_sem();
3945        kfree(font.data);
3946        return rc;
3947}
3948
3949static int con_font_default(struct vc_data *vc, struct console_font_op *op)
3950{
3951        struct console_font font = {.width = op->width, .height = op->height};
3952        char name[MAX_FONT_NAME];
3953        char *s = name;
3954        int rc;
3955
3956        if (vc->vc_mode != KD_TEXT)
3957                return -EINVAL;
3958
3959        if (!op->data)
3960                s = NULL;
3961        else if (strncpy_from_user(name, op->data, MAX_FONT_NAME - 1) < 0)
3962                return -EFAULT;
3963        else
3964                name[MAX_FONT_NAME - 1] = 0;
3965
3966        acquire_console_sem();
3967        if (vc->vc_sw->con_font_default)
3968                rc = vc->vc_sw->con_font_default(vc, &font, s);
3969        else
3970                rc = -ENOSYS;
3971        release_console_sem();
3972        if (!rc) {
3973                op->width = font.width;
3974                op->height = font.height;
3975        }
3976        return rc;
3977}
3978
3979static int con_font_copy(struct vc_data *vc, struct console_font_op *op)
3980{
3981        int con = op->height;
3982        int rc;
3983
3984        if (vc->vc_mode != KD_TEXT)
3985                return -EINVAL;
3986
3987        acquire_console_sem();
3988        if (!vc->vc_sw->con_font_copy)
3989                rc = -ENOSYS;
3990        else if (con < 0 || !vc_cons_allocated(con))
3991                rc = -ENOTTY;
3992        else if (con == vc->vc_num)     /* nothing to do */
3993                rc = 0;
3994        else
3995                rc = vc->vc_sw->con_font_copy(vc, con);
3996        release_console_sem();
3997        return rc;
3998}
3999
4000int con_font_op(struct vc_data *vc, struct console_font_op *op)
4001{
4002        switch (op->op) {
4003        case KD_FONT_OP_SET:
4004                return con_font_set(vc, op);
4005        case KD_FONT_OP_GET:
4006                return con_font_get(vc, op);
4007        case KD_FONT_OP_SET_DEFAULT:
4008                return con_font_default(vc, op);
4009        case KD_FONT_OP_COPY:
4010                return con_font_copy(vc, op);
4011        }
4012        return -ENOSYS;
4013}
4014
4015/*
4016 *      Interface exported to selection and vcs.
4017 */
4018
4019/* used by selection */
4020u16 screen_glyph(struct vc_data *vc, int offset)
4021{
4022        u16 w = scr_readw(screenpos(vc, offset, 1));
4023        u16 c = w & 0xff;
4024
4025        if (w & vc->vc_hi_font_mask)
4026                c |= 0x100;
4027        return c;
4028}
4029EXPORT_SYMBOL_GPL(screen_glyph);
4030
4031/* used by vcs - note the word offset */
4032unsigned short *screen_pos(struct vc_data *vc, int w_offset, int viewed)
4033{
4034        return screenpos(vc, 2 * w_offset, viewed);
4035}
4036
4037void getconsxy(struct vc_data *vc, unsigned char *p)
4038{
4039        p[0] = vc->vc_x;
4040        p[1] = vc->vc_y;
4041}
4042
4043void putconsxy(struct vc_data *vc, unsigned char *p)
4044{
4045        hide_cursor(vc);
4046        gotoxy(vc, p[0], p[1]);
4047        set_cursor(vc);
4048}
4049
4050u16 vcs_scr_readw(struct vc_data *vc, const u16 *org)
4051{
4052        if ((unsigned long)org == vc->vc_pos && softcursor_original != -1)
4053                return softcursor_original;
4054        return scr_readw(org);
4055}
4056
4057void vcs_scr_writew(struct vc_data *vc, u16 val, u16 *org)
4058{
4059        scr_writew(val, org);
4060        if ((unsigned long)org == vc->vc_pos) {
4061                softcursor_original = -1;
4062                add_softcursor(vc);
4063        }
4064}
4065
4066/*
4067 *      Visible symbols for modules
4068 */
4069
4070EXPORT_SYMBOL(color_table);
4071EXPORT_SYMBOL(default_red);
4072EXPORT_SYMBOL(default_grn);
4073EXPORT_SYMBOL(default_blu);
4074EXPORT_SYMBOL(update_region);
4075EXPORT_SYMBOL(redraw_screen);
4076EXPORT_SYMBOL(vc_resize);
4077EXPORT_SYMBOL(fg_console);
4078EXPORT_SYMBOL(console_blank_hook);
4079EXPORT_SYMBOL(console_blanked);
4080EXPORT_SYMBOL(vc_cons);
4081#ifndef VT_SINGLE_DRIVER
4082EXPORT_SYMBOL(take_over_console);
4083EXPORT_SYMBOL(give_up_console);
4084#endif
4085