linux-old/drivers/char/console.c
<<
>>
Prefs
   1/*
   2 *  linux/drivers/char/console.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 *   Note that the abstract console driver allows all consoles to be of
  44 *   potentially different sizes, so the following variables depend on the
  45 *   current console (currcons):
  46 *
  47 *     - video_num_columns
  48 *     - video_num_lines
  49 *     - video_size_row
  50 *     - can_do_color
  51 *
  52 *   The abstract console driver provides a generic interface for a text
  53 *   console. It supports VGA text mode, frame buffer based graphical consoles
  54 *   and special graphics processors that are only accessible through some
  55 *   registers (e.g. a TMS340x0 GSP).
  56 *
  57 *   The interface to the hardware is specified using a special structure
  58 *   (struct consw) which contains function pointers to console operations
  59 *   (see <linux/console.h> for more information).
  60 *
  61 * Support for changeable cursor shape
  62 * by Pavel Machek <pavel@atrey.karlin.mff.cuni.cz>, August 1997
  63 *
  64 * Ported to i386 and con_scrolldelta fixed
  65 * by Emmanuel Marty <core@ggi-project.org>, April 1998
  66 *
  67 * Resurrected character buffers in videoram plus lots of other trickery
  68 * by Martin Mares <mj@atrey.karlin.mff.cuni.cz>, July 1998
  69 *
  70 * Removed old-style timers, introduced console_timer, made timer
  71 * deletion SMP-safe.  17Jun00, Andrew Morton <andrewm@uow.edu.au>
  72 *
  73 * Removed console_lock, enabled interrupts across all console operations
  74 * 13 March 2001, Andrew Morton
  75 */
  76
  77#include <linux/module.h>
  78#include <linux/sched.h>
  79#include <linux/tty.h>
  80#include <linux/tty_flip.h>
  81#include <linux/kernel.h>
  82#include <linux/string.h>
  83#include <linux/errno.h>
  84#include <linux/kd.h>
  85#include <linux/slab.h>
  86#include <linux/major.h>
  87#include <linux/mm.h>
  88#include <linux/console.h>
  89#include <linux/init.h>
  90#include <linux/devfs_fs_kernel.h>
  91#include <linux/vt_kern.h>
  92#include <linux/selection.h>
  93#include <linux/console_struct.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/config.h>
  99#include <linux/version.h>
 100#include <linux/tqueue.h>
 101#include <linux/bootmem.h>
 102#include <linux/pm.h>
 103#include <linux/smp_lock.h>
 104
 105#include <asm/io.h>
 106#include <asm/system.h>
 107#include <asm/uaccess.h>
 108#include <asm/bitops.h>
 109
 110#include "console_macros.h"
 111
 112
 113const struct consw *conswitchp;
 114
 115static void __console_callback(void);
 116
 117/* A bitmap for codes <32. A bit of 1 indicates that the code
 118 * corresponding to that bit number invokes some special action
 119 * (such as cursor movement) and should not be displayed as a
 120 * glyph unless the disp_ctrl mode is explicitly enabled.
 121 */
 122#define CTRL_ACTION 0x0d00ff81
 123#define CTRL_ALWAYS 0x0800f501  /* Cannot be overridden by disp_ctrl */
 124
 125/*
 126 * Here is the default bell parameters: 750HZ, 1/8th of a second
 127 */
 128#define DEFAULT_BELL_PITCH      750
 129#define DEFAULT_BELL_DURATION   (HZ/8)
 130
 131extern void vcs_make_devfs (unsigned int index, int unregister);
 132
 133#ifndef MIN
 134#define MIN(a,b)        ((a) < (b) ? (a) : (b))
 135#endif
 136
 137static struct tty_struct *console_table[MAX_NR_CONSOLES];
 138static struct termios *console_termios[MAX_NR_CONSOLES];
 139static struct termios *console_termios_locked[MAX_NR_CONSOLES];
 140struct vc vc_cons [MAX_NR_CONSOLES];
 141
 142#ifndef VT_SINGLE_DRIVER
 143static const struct consw *con_driver_map[MAX_NR_CONSOLES];
 144#endif
 145
 146static int con_open(struct tty_struct *, struct file *);
 147static void vc_init(unsigned int console, unsigned int rows,
 148                    unsigned int cols, int do_clear);
 149static void blank_screen(unsigned long dummy);
 150static void gotoxy(int currcons, int new_x, int new_y);
 151static void save_cur(int currcons);
 152static void reset_terminal(int currcons, int do_clear);
 153static void con_flush_chars(struct tty_struct *tty);
 154static void set_vesa_blanking(unsigned long arg);
 155static void set_cursor(int currcons);
 156static void hide_cursor(int currcons);
 157static void unblank_screen_t(unsigned long dummy);
 158static void console_callback(void *ignored);
 159
 160static int printable;           /* Is console ready for printing? */
 161
 162int do_poke_blanked_console;
 163int console_blanked;
 164
 165static int vesa_blank_mode; /* 0:none 1:suspendV 2:suspendH 3:powerdown */
 166static int blankinterval = 10*60*HZ;
 167static int vesa_off_interval;
 168
 169static struct tq_struct console_callback_tq = {
 170        routine: console_callback,
 171};
 172
 173/*
 174 * fg_console is the current virtual console,
 175 * last_console is the last used one,
 176 * want_console is the console we want to switch to,
 177 * kmsg_redirect is the console for kernel messages,
 178 */
 179int fg_console;
 180int last_console;
 181int want_console = -1;
 182int kmsg_redirect;
 183
 184/*
 185 * For each existing display, we have a pointer to console currently visible
 186 * on that display, allowing consoles other than fg_console to be refreshed
 187 * appropriately. Unless the low-level driver supplies its own display_fg
 188 * variable, we use this one for the "master display".
 189 */
 190static struct vc_data *master_display_fg;
 191
 192/*
 193 * Unfortunately, we need to delay tty echo when we're currently writing to the
 194 * console since the code is (and always was) not re-entrant, so we schedule
 195 * all flip requests to process context with schedule-task() and run it from
 196 * console_callback().
 197 */
 198
 199/*
 200 * For the same reason, we defer scrollback to the console callback.
 201 */
 202static int scrollback_delta;
 203
 204/*
 205 * Hook so that the power management routines can (un)blank
 206 * the console on our behalf.
 207 */
 208int (*console_blank_hook)(int);
 209
 210static struct timer_list console_timer;
 211
 212/*
 213 *      Low-Level Functions
 214 */
 215
 216#define IS_FG (currcons == fg_console)
 217#define IS_VISIBLE CON_IS_VISIBLE(vc_cons[currcons].d)
 218
 219#ifdef VT_BUF_VRAM_ONLY
 220#define DO_UPDATE 0
 221#else
 222#define DO_UPDATE IS_VISIBLE
 223#endif
 224
 225static int pm_con_request(struct pm_dev *dev, pm_request_t rqst, void *data);
 226static struct pm_dev *pm_con;
 227
 228static inline unsigned short *screenpos(int currcons, int offset, int viewed)
 229{
 230        unsigned short *p;
 231        
 232        if (!viewed)
 233                p = (unsigned short *)(origin + offset);
 234        else if (!sw->con_screen_pos)
 235                p = (unsigned short *)(visible_origin + offset);
 236        else
 237                p = sw->con_screen_pos(vc_cons[currcons].d, offset);
 238        return p;
 239}
 240
 241static inline void scrolldelta(int lines)
 242{
 243        scrollback_delta += lines;
 244        schedule_console_callback();
 245}
 246
 247extern int machine_paniced; 
 248
 249void schedule_console_callback(void)
 250{
 251        /* Don't care about locking after panic - but I want to switch the console
 252           NOW */ 
 253        if (machine_paniced)
 254                __console_callback(); 
 255        else
 256                schedule_task(&console_callback_tq);
 257}
 258
 259static void scrup(int currcons, unsigned int t, unsigned int b, int nr)
 260{
 261        unsigned short *d, *s;
 262
 263        if (t+nr >= b)
 264                nr = b - t - 1;
 265        if (b > video_num_lines || t >= b || nr < 1)
 266                return;
 267        if (IS_VISIBLE && sw->con_scroll(vc_cons[currcons].d, t, b, SM_UP, nr))
 268                return;
 269        d = (unsigned short *) (origin+video_size_row*t);
 270        s = (unsigned short *) (origin+video_size_row*(t+nr));
 271        scr_memcpyw(d, s, (b-t-nr) * video_size_row);
 272        scr_memsetw(d + (b-t-nr) * video_num_columns, video_erase_char, video_size_row*nr);
 273}
 274
 275static void
 276scrdown(int currcons, unsigned int t, unsigned int b, int nr)
 277{
 278        unsigned short *s;
 279        unsigned int step;
 280
 281        if (t+nr >= b)
 282                nr = b - t - 1;
 283        if (b > video_num_lines || t >= b || nr < 1)
 284                return;
 285        if (IS_VISIBLE && sw->con_scroll(vc_cons[currcons].d, t, b, SM_DOWN, nr))
 286                return;
 287        s = (unsigned short *) (origin+video_size_row*t);
 288        step = video_num_columns * nr;
 289        scr_memmovew(s + step, s, (b-t-nr)*video_size_row);
 290        scr_memsetw(s, video_erase_char, 2*step);
 291}
 292
 293static void do_update_region(int currcons, unsigned long start, int count)
 294{
 295#ifndef VT_BUF_VRAM_ONLY
 296        unsigned int xx, yy, offset;
 297        u16 *p;
 298
 299        p = (u16 *) start;
 300        if (!sw->con_getxy) {
 301                offset = (start - origin) / 2;
 302                xx = offset % video_num_columns;
 303                yy = offset / video_num_columns;
 304        } else {
 305                int nxx, nyy;
 306                start = sw->con_getxy(vc_cons[currcons].d, start, &nxx, &nyy);
 307                xx = nxx; yy = nyy;
 308        }
 309        for(;;) {
 310                u16 attrib = scr_readw(p) & 0xff00;
 311                int startx = xx;
 312                u16 *q = p;
 313                while (xx < video_num_columns && count) {
 314                        if (attrib != (scr_readw(p) & 0xff00)) {
 315                                if (p > q)
 316                                        sw->con_putcs(vc_cons[currcons].d, q, p-q, yy, startx);
 317                                startx = xx;
 318                                q = p;
 319                                attrib = scr_readw(p) & 0xff00;
 320                        }
 321                        p++;
 322                        xx++;
 323                        count--;
 324                }
 325                if (p > q)
 326                        sw->con_putcs(vc_cons[currcons].d, q, p-q, yy, startx);
 327                if (!count)
 328                        break;
 329                xx = 0;
 330                yy++;
 331                if (sw->con_getxy) {
 332                        p = (u16 *)start;
 333                        start = sw->con_getxy(vc_cons[currcons].d, start, NULL, NULL);
 334                }
 335        }
 336#endif
 337}
 338
 339void update_region(int currcons, unsigned long start, int count)
 340{
 341        if (DO_UPDATE) {
 342                hide_cursor(currcons);
 343                do_update_region(currcons, start, count);
 344                set_cursor(currcons);
 345        }
 346}
 347
 348/* Structure of attributes is hardware-dependent */
 349
 350static u8 build_attr(int currcons, u8 _color, u8 _intensity, u8 _blink, u8 _underline, u8 _reverse)
 351{
 352        if (sw->con_build_attr)
 353                return sw->con_build_attr(vc_cons[currcons].d, _color, _intensity, _blink, _underline, _reverse);
 354
 355#ifndef VT_BUF_VRAM_ONLY
 356/*
 357 * ++roman: I completely changed the attribute format for monochrome
 358 * mode (!can_do_color). The formerly used MDA (monochrome display
 359 * adapter) format didn't allow the combination of certain effects.
 360 * Now the attribute is just a bit vector:
 361 *  Bit 0..1: intensity (0..2)
 362 *  Bit 2   : underline
 363 *  Bit 3   : reverse
 364 *  Bit 7   : blink
 365 */
 366        {
 367        u8 a = color;
 368        if (!can_do_color)
 369                return _intensity |
 370                       (_underline ? 4 : 0) |
 371                       (_reverse ? 8 : 0) |
 372                       (_blink ? 0x80 : 0);
 373        if (_underline)
 374                a = (a & 0xf0) | ulcolor;
 375        else if (_intensity == 0)
 376                a = (a & 0xf0) | halfcolor;
 377        if (_reverse)
 378                a = ((a) & 0x88) | ((((a) >> 4) | ((a) << 4)) & 0x77);
 379        if (_blink)
 380                a ^= 0x80;
 381        if (_intensity == 2)
 382                a ^= 0x08;
 383        if (hi_font_mask == 0x100)
 384                a <<= 1;
 385        return a;
 386        }
 387#else
 388        return 0;
 389#endif
 390}
 391
 392static void update_attr(int currcons)
 393{
 394        attr = build_attr(currcons, color, intensity, blink, underline, reverse ^ decscnm);
 395        video_erase_char = (build_attr(currcons, color, 1, blink, 0, decscnm) << 8) | ' ';
 396}
 397
 398/* Note: inverting the screen twice should revert to the original state */
 399
 400void invert_screen(int currcons, int offset, int count, int viewed)
 401{
 402        unsigned short *p;
 403
 404        count /= 2;
 405        p = screenpos(currcons, offset, viewed);
 406        if (sw->con_invert_region)
 407                sw->con_invert_region(vc_cons[currcons].d, p, count);
 408#ifndef VT_BUF_VRAM_ONLY
 409        else {
 410                u16 *q = p;
 411                int cnt = count;
 412                u16 a;
 413
 414                if (!can_do_color) {
 415                        while (cnt--) {
 416                            a = scr_readw(q);
 417                            a ^= 0x0800;
 418                            scr_writew(a, q);
 419                            q++;
 420                        }
 421                } else if (hi_font_mask == 0x100) {
 422                        while (cnt--) {
 423                                a = scr_readw(q);
 424                                a = ((a) & 0x11ff) | (((a) & 0xe000) >> 4) | (((a) & 0x0e00) << 4);
 425                                scr_writew(a, q);
 426                                q++;
 427                        }
 428                } else {
 429                        while (cnt--) {
 430                                a = scr_readw(q);
 431                                a = ((a) & 0x88ff) | (((a) & 0x7000) >> 4) | (((a) & 0x0700) << 4);
 432                                scr_writew(a, q);
 433                                q++;
 434                        }
 435                }
 436        }
 437#endif
 438        if (DO_UPDATE)
 439                do_update_region(currcons, (unsigned long) p, count);
 440}
 441
 442/* used by selection: complement pointer position */
 443void complement_pos(int currcons, int offset)
 444{
 445        static unsigned short *p;
 446        static unsigned short old;
 447        static unsigned short oldx, oldy;
 448
 449        if (p) {
 450                scr_writew(old, p);
 451                if (DO_UPDATE)
 452                        sw->con_putc(vc_cons[currcons].d, old, oldy, oldx);
 453        }
 454        if (offset == -1)
 455                p = NULL;
 456        else {
 457                unsigned short new;
 458                p = screenpos(currcons, offset, 1);
 459                old = scr_readw(p);
 460                new = old ^ complement_mask;
 461                scr_writew(new, p);
 462                if (DO_UPDATE) {
 463                        oldx = (offset >> 1) % video_num_columns;
 464                        oldy = (offset >> 1) / video_num_columns;
 465                        sw->con_putc(vc_cons[currcons].d, new, oldy, oldx);
 466                }
 467        }
 468}
 469
 470static void insert_char(int currcons, unsigned int nr)
 471{
 472        unsigned short *p, *q = (unsigned short *) pos;
 473
 474        p = q + video_num_columns - nr - x;
 475        while (--p >= q)
 476                scr_writew(scr_readw(p), p + nr);
 477        scr_memsetw(q, video_erase_char, nr*2);
 478        need_wrap = 0;
 479        if (DO_UPDATE) {
 480                unsigned short oldattr = attr;
 481                sw->con_bmove(vc_cons[currcons].d,y,x,y,x+nr,1,
 482                              video_num_columns-x-nr);
 483                attr = video_erase_char >> 8;
 484                while (nr--)
 485                        sw->con_putc(vc_cons[currcons].d,
 486                                     video_erase_char,y,x+nr);
 487                attr = oldattr;
 488        }
 489}
 490
 491static void delete_char(int currcons, unsigned int nr)
 492{
 493        unsigned int i = x;
 494        unsigned short *p = (unsigned short *) pos;
 495
 496        while (++i <= video_num_columns - nr) {
 497                scr_writew(scr_readw(p+nr), p);
 498                p++;
 499        }
 500        scr_memsetw(p, video_erase_char, nr*2);
 501        need_wrap = 0;
 502        if (DO_UPDATE) {
 503                unsigned short oldattr = attr;
 504                sw->con_bmove(vc_cons[currcons].d, y, x+nr, y, x, 1,
 505                              video_num_columns-x-nr);
 506                attr = video_erase_char >> 8;
 507                while (nr--)
 508                        sw->con_putc(vc_cons[currcons].d,
 509                                     video_erase_char, y,
 510                                     video_num_columns-1-nr);
 511                attr = oldattr;
 512        }
 513}
 514
 515static int softcursor_original;
 516
 517static void add_softcursor(int currcons)
 518{
 519        int i = scr_readw((u16 *) pos);
 520        u32 type = cursor_type;
 521
 522        if (! (type & 0x10)) return;
 523        if (softcursor_original != -1) return;
 524        softcursor_original = i;
 525        i |= ((type >> 8) & 0xff00 );
 526        i ^= ((type) & 0xff00 );
 527        if ((type & 0x20) && ((softcursor_original & 0x7000) == (i & 0x7000))) i ^= 0x7000;
 528        if ((type & 0x40) && ((i & 0x700) == ((i & 0x7000) >> 4))) i ^= 0x0700;
 529        scr_writew(i, (u16 *) pos);
 530        if (DO_UPDATE)
 531                sw->con_putc(vc_cons[currcons].d, i, y, x);
 532}
 533
 534static void hide_cursor(int currcons)
 535{
 536        if (currcons == sel_cons)
 537                clear_selection();
 538        if (softcursor_original != -1) {
 539                scr_writew(softcursor_original,(u16 *) pos);
 540                if (DO_UPDATE)
 541                        sw->con_putc(vc_cons[currcons].d, softcursor_original, y, x);
 542                softcursor_original = -1;
 543        }
 544        sw->con_cursor(vc_cons[currcons].d,CM_ERASE);
 545}
 546
 547static void set_cursor(int currcons)
 548{
 549    if (!IS_FG || console_blanked || vcmode == KD_GRAPHICS)
 550        return;
 551    if (deccm) {
 552        if (currcons == sel_cons)
 553                clear_selection();
 554        add_softcursor(currcons);
 555        if ((cursor_type & 0x0f) != 1)
 556            sw->con_cursor(vc_cons[currcons].d,CM_DRAW);
 557    } else
 558        hide_cursor(currcons);
 559}
 560
 561static void set_origin(int currcons)
 562{
 563        if (!IS_VISIBLE ||
 564            !sw->con_set_origin ||
 565            !sw->con_set_origin(vc_cons[currcons].d))
 566                origin = (unsigned long) screenbuf;
 567        visible_origin = origin;
 568        scr_end = origin + screenbuf_size;
 569        pos = origin + video_size_row*y + 2*x;
 570}
 571
 572static inline void save_screen(int currcons)
 573{
 574        if (sw->con_save_screen)
 575                sw->con_save_screen(vc_cons[currcons].d);
 576}
 577
 578/*
 579 *      Redrawing of screen
 580 */
 581
 582void redraw_screen(int new_console, int is_switch)
 583{
 584        int redraw = 1;
 585        int currcons, old_console;
 586
 587        if (!vc_cons_allocated(new_console)) {
 588                /* strange ... */
 589                /* printk("redraw_screen: tty %d not allocated ??\n", new_console+1); */
 590                return;
 591        }
 592
 593        if (is_switch) {
 594                currcons = fg_console;
 595                hide_cursor(currcons);
 596                if (fg_console != new_console) {
 597                        struct vc_data **display = vc_cons[new_console].d->vc_display_fg;
 598                        old_console = (*display) ? (*display)->vc_num : fg_console;
 599                        *display = vc_cons[new_console].d;
 600                        fg_console = new_console;
 601                        currcons = old_console;
 602                        if (!IS_VISIBLE) {
 603                                save_screen(currcons);
 604                                set_origin(currcons);
 605                        }
 606                        currcons = new_console;
 607                        if (old_console == new_console)
 608                                redraw = 0;
 609                }
 610        } else {
 611                currcons = new_console;
 612                hide_cursor(currcons);
 613        }
 614
 615        if (redraw) {
 616                int update;
 617                set_origin(currcons);
 618                update = sw->con_switch(vc_cons[currcons].d);
 619                set_palette(currcons);
 620                if (update && vcmode != KD_GRAPHICS)
 621                        do_update_region(currcons, origin, screenbuf_size/2);
 622        }
 623        set_cursor(currcons);
 624        if (is_switch) {
 625                set_leds();
 626                compute_shiftstate();
 627        }
 628}
 629
 630/*
 631 *      Allocation, freeing and resizing of VTs.
 632 */
 633
 634int vc_cons_allocated(unsigned int i)
 635{
 636        return (i < MAX_NR_CONSOLES && vc_cons[i].d);
 637}
 638
 639static void visual_init(int currcons, int init)
 640{
 641    /* ++Geert: sw->con_init determines console size */
 642    sw = conswitchp;
 643#ifndef VT_SINGLE_DRIVER
 644    if (con_driver_map[currcons])
 645        sw = con_driver_map[currcons];
 646#endif
 647    cons_num = currcons;
 648    display_fg = &master_display_fg;
 649    vc_cons[currcons].d->vc_uni_pagedir_loc = &vc_cons[currcons].d->vc_uni_pagedir;
 650    vc_cons[currcons].d->vc_uni_pagedir = 0;
 651    hi_font_mask = 0;
 652    complement_mask = 0;
 653    can_do_color = 0;
 654    sw->con_init(vc_cons[currcons].d, init);
 655    if (!complement_mask)
 656        complement_mask = can_do_color ? 0x7700 : 0x0800;
 657    s_complement_mask = complement_mask;
 658    video_size_row = video_num_columns<<1;
 659    screenbuf_size = video_num_lines*video_size_row;
 660}
 661
 662int vc_allocate(unsigned int currcons)  /* return 0 on success */
 663{
 664        if (currcons >= MAX_NR_CONSOLES)
 665                return -ENXIO;
 666        if (!vc_cons[currcons].d) {
 667            long p, q;
 668
 669            /* prevent users from taking too much memory */
 670            if (currcons >= MAX_NR_USER_CONSOLES && !capable(CAP_SYS_RESOURCE))
 671              return -EPERM;
 672
 673            /* due to the granularity of kmalloc, we waste some memory here */
 674            /* the alloc is done in two steps, to optimize the common situation
 675               of a 25x80 console (structsize=216, screenbuf_size=4000) */
 676            /* although the numbers above are not valid since long ago, the
 677               point is still up-to-date and the comment still has its value
 678               even if only as a historical artifact.  --mj, July 1998 */
 679            p = (long) kmalloc(structsize, GFP_KERNEL);
 680            if (!p)
 681                return -ENOMEM;
 682            memset((void *)p, 0, structsize);
 683            vc_cons[currcons].d = (struct vc_data *)p;
 684            vt_cons[currcons] = (struct vt_struct *)(p+sizeof(struct vc_data));
 685            visual_init(currcons, 1);
 686            if (!*vc_cons[currcons].d->vc_uni_pagedir_loc)
 687                con_set_default_unimap(currcons);
 688            q = (long)kmalloc(screenbuf_size, GFP_KERNEL);
 689            if (!q) {
 690                kfree((char *) p);
 691                vc_cons[currcons].d = NULL;
 692                vt_cons[currcons] = NULL;
 693                return -ENOMEM;
 694            }
 695            screenbuf = (unsigned short *) q;
 696            kmalloced = 1;
 697            vc_init(currcons, video_num_lines, video_num_columns, 1);
 698
 699            if (!pm_con) {
 700                    pm_con = pm_register(PM_SYS_DEV,
 701                                         PM_SYS_VGA,
 702                                         pm_con_request);
 703            }
 704        }
 705        return 0;
 706}
 707
 708#define VC_RESIZE_MAXCOL (32767)
 709#define VC_RESIZE_MAXROW (32767)
 710
 711/*
 712 * Change # of rows and columns (0 means unchanged/the size of fg_console)
 713 * [this is to be used together with some user program
 714 * like resize that changes the hardware videomode]
 715 */
 716int vc_resize(unsigned int lines, unsigned int cols,
 717              unsigned int first, unsigned int last)
 718{
 719        unsigned int cc, ll, ss, sr, todo = 0;
 720        unsigned int currcons = fg_console, i;
 721        unsigned short *newscreens[MAX_NR_CONSOLES];
 722
 723        if (cols > VC_RESIZE_MAXCOL || lines > VC_RESIZE_MAXROW)
 724                return -EINVAL;
 725
 726        cc = (cols ? cols : video_num_columns);
 727        ll = (lines ? lines : video_num_lines);
 728        sr = cc << 1;
 729        ss = sr * ll;
 730
 731        for (currcons = first; currcons <= last; currcons++) {
 732                if (!vc_cons_allocated(currcons) ||
 733                    (cc == video_num_columns && ll == video_num_lines))
 734                        newscreens[currcons] = NULL;
 735                else {
 736                        unsigned short *p = (unsigned short *) kmalloc(ss, GFP_USER);
 737                        if (!p) {
 738                                for (i = first; i < currcons; i++)
 739                                        if (newscreens[i])
 740                                                kfree(newscreens[i]);
 741                                return -ENOMEM;
 742                        }
 743                        newscreens[currcons] = p;
 744                        todo++;
 745                }
 746        }
 747        if (!todo)
 748                return 0;
 749
 750        for (currcons = first; currcons <= last; currcons++) {
 751                unsigned int occ, oll, oss, osr;
 752                unsigned long ol, nl, nlend, rlth, rrem;
 753                if (!newscreens[currcons] || !vc_cons_allocated(currcons))
 754                        continue;
 755
 756                oll = video_num_lines;
 757                occ = video_num_columns;
 758                osr = video_size_row;
 759                oss = screenbuf_size;
 760
 761                video_num_lines = ll;
 762                video_num_columns = cc;
 763                video_size_row = sr;
 764                screenbuf_size = ss;
 765
 766                rlth = MIN(osr, sr);
 767                rrem = sr - rlth;
 768                ol = origin;
 769                nl = (long) newscreens[currcons];
 770                nlend = nl + ss;
 771                if (ll < oll)
 772                        ol += (oll - ll) * osr;
 773
 774                update_attr(currcons);
 775
 776                while (ol < scr_end) {
 777                        scr_memcpyw((unsigned short *) nl, (unsigned short *) ol, rlth);
 778                        if (rrem)
 779                                scr_memsetw((void *)(nl + rlth), video_erase_char, rrem);
 780                        ol += osr;
 781                        nl += sr;
 782                }
 783                if (nlend > nl)
 784                        scr_memsetw((void *) nl, video_erase_char, nlend - nl);
 785                if (kmalloced)
 786                        kfree(screenbuf);
 787                screenbuf = newscreens[currcons];
 788                kmalloced = 1;
 789                screenbuf_size = ss;
 790                set_origin(currcons);
 791
 792                /* do part of a reset_terminal() */
 793                top = 0;
 794                bottom = video_num_lines;
 795                gotoxy(currcons, x, y);
 796                save_cur(currcons);
 797
 798                if (console_table[currcons]) {
 799                        struct winsize ws, *cws = &console_table[currcons]->winsize;
 800                        memset(&ws, 0, sizeof(ws));
 801                        ws.ws_row = video_num_lines;
 802                        ws.ws_col = video_num_columns;
 803                        if ((ws.ws_row != cws->ws_row || ws.ws_col != cws->ws_col) &&
 804                            console_table[currcons]->pgrp > 0)
 805                                kill_pg(console_table[currcons]->pgrp, SIGWINCH, 1);
 806                        *cws = ws;
 807                }
 808
 809                if (IS_VISIBLE)
 810                        update_screen(currcons);
 811        }
 812
 813        return 0;
 814}
 815
 816
 817void vc_disallocate(unsigned int currcons)
 818{
 819        acquire_console_sem();
 820        if (vc_cons_allocated(currcons)) {
 821            sw->con_deinit(vc_cons[currcons].d);
 822            if (kmalloced)
 823                kfree(screenbuf);
 824            if (currcons >= MIN_NR_CONSOLES)
 825                kfree(vc_cons[currcons].d);
 826            vc_cons[currcons].d = NULL;
 827        }
 828        release_console_sem();
 829}
 830
 831/*
 832 *      VT102 emulator
 833 */
 834
 835#define set_kbd(x) set_vc_kbd_mode(kbd_table+currcons,x)
 836#define clr_kbd(x) clr_vc_kbd_mode(kbd_table+currcons,x)
 837#define is_kbd(x) vc_kbd_mode(kbd_table+currcons,x)
 838
 839#define decarm          VC_REPEAT
 840#define decckm          VC_CKMODE
 841#define kbdapplic       VC_APPLIC
 842#define lnm             VC_CRLF
 843
 844/*
 845 * this is what the terminal answers to a ESC-Z or csi0c query.
 846 */
 847#define VT100ID "\033[?1;2c"
 848#define VT102ID "\033[?6c"
 849
 850unsigned char color_table[] = { 0, 4, 2, 6, 1, 5, 3, 7,
 851                                       8,12,10,14, 9,13,11,15 };
 852
 853/* the default colour table, for VGA+ colour systems */
 854int default_red[] = {0x00,0xaa,0x00,0xaa,0x00,0xaa,0x00,0xaa,
 855    0x55,0xff,0x55,0xff,0x55,0xff,0x55,0xff};
 856int default_grn[] = {0x00,0x00,0xaa,0x55,0x00,0x00,0xaa,0xaa,
 857    0x55,0x55,0xff,0xff,0x55,0x55,0xff,0xff};
 858int default_blu[] = {0x00,0x00,0x00,0x00,0xaa,0xaa,0xaa,0xaa,
 859    0x55,0x55,0x55,0x55,0xff,0xff,0xff,0xff};
 860
 861/*
 862 * gotoxy() must verify all boundaries, because the arguments
 863 * might also be negative. If the given position is out of
 864 * bounds, the cursor is placed at the nearest margin.
 865 */
 866static void gotoxy(int currcons, int new_x, int new_y)
 867{
 868        int min_y, max_y;
 869
 870        if (new_x < 0)
 871                x = 0;
 872        else
 873                if (new_x >= video_num_columns)
 874                        x = video_num_columns - 1;
 875                else
 876                        x = new_x;
 877        if (decom) {
 878                min_y = top;
 879                max_y = bottom;
 880        } else {
 881                min_y = 0;
 882                max_y = video_num_lines;
 883        }
 884        if (new_y < min_y)
 885                y = min_y;
 886        else if (new_y >= max_y)
 887                y = max_y - 1;
 888        else
 889                y = new_y;
 890        pos = origin + y*video_size_row + (x<<1);
 891        need_wrap = 0;
 892}
 893
 894/* for absolute user moves, when decom is set */
 895static void gotoxay(int currcons, int new_x, int new_y)
 896{
 897        gotoxy(currcons, new_x, decom ? (top+new_y) : new_y);
 898}
 899
 900void scrollback(int lines)
 901{
 902        int currcons = fg_console;
 903
 904        if (!lines)
 905                lines = video_num_lines/2;
 906        scrolldelta(-lines);
 907}
 908
 909void scrollfront(int lines)
 910{
 911        int currcons = fg_console;
 912
 913        if (!lines)
 914                lines = video_num_lines/2;
 915        scrolldelta(lines);
 916}
 917
 918static void lf(int currcons)
 919{
 920        /* don't scroll if above bottom of scrolling region, or
 921         * if below scrolling region
 922         */
 923        if (y+1 == bottom)
 924                scrup(currcons,top,bottom,1);
 925        else if (y < video_num_lines-1) {
 926                y++;
 927                pos += video_size_row;
 928        }
 929        need_wrap = 0;
 930}
 931
 932static void ri(int currcons)
 933{
 934        /* don't scroll if below top of scrolling region, or
 935         * if above scrolling region
 936         */
 937        if (y == top)
 938                scrdown(currcons,top,bottom,1);
 939        else if (y > 0) {
 940                y--;
 941                pos -= video_size_row;
 942        }
 943        need_wrap = 0;
 944}
 945
 946static inline void cr(int currcons)
 947{
 948        pos -= x<<1;
 949        need_wrap = x = 0;
 950}
 951
 952static inline void bs(int currcons)
 953{
 954        if (x) {
 955                pos -= 2;
 956                x--;
 957                need_wrap = 0;
 958        }
 959}
 960
 961static inline void del(int currcons)
 962{
 963        /* ignored */
 964}
 965
 966static void csi_J(int currcons, int vpar)
 967{
 968        unsigned int count;
 969        unsigned short * start;
 970
 971        switch (vpar) {
 972                case 0: /* erase from cursor to end of display */
 973                        count = (scr_end-pos)>>1;
 974                        start = (unsigned short *) pos;
 975                        if (DO_UPDATE) {
 976                                /* do in two stages */
 977                                sw->con_clear(vc_cons[currcons].d, y, x, 1,
 978                                              video_num_columns-x);
 979                                sw->con_clear(vc_cons[currcons].d, y+1, 0,
 980                                              video_num_lines-y-1,
 981                                              video_num_columns);
 982                        }
 983                        break;
 984                case 1: /* erase from start to cursor */
 985                        count = ((pos-origin)>>1)+1;
 986                        start = (unsigned short *) origin;
 987                        if (DO_UPDATE) {
 988                                /* do in two stages */
 989                                sw->con_clear(vc_cons[currcons].d, 0, 0, y,
 990                                              video_num_columns);
 991                                sw->con_clear(vc_cons[currcons].d, y, 0, 1,
 992                                              x + 1);
 993                        }
 994                        break;
 995                case 2: /* erase whole display */
 996                        count = video_num_columns * video_num_lines;
 997                        start = (unsigned short *) origin;
 998                        if (DO_UPDATE)
 999                                sw->con_clear(vc_cons[currcons].d, 0, 0,
1000                                              video_num_lines,
1001                                              video_num_columns);
1002                        break;
1003                default:
1004                        return;
1005        }
1006        scr_memsetw(start, video_erase_char, 2*count);
1007        need_wrap = 0;
1008}
1009
1010static void csi_K(int currcons, int vpar)
1011{
1012        unsigned int count;
1013        unsigned short * start;
1014
1015        switch (vpar) {
1016                case 0: /* erase from cursor to end of line */
1017                        count = video_num_columns-x;
1018                        start = (unsigned short *) pos;
1019                        if (DO_UPDATE)
1020                                sw->con_clear(vc_cons[currcons].d, y, x, 1,
1021                                              video_num_columns-x);
1022                        break;
1023                case 1: /* erase from start of line to cursor */
1024                        start = (unsigned short *) (pos - (x<<1));
1025                        count = x+1;
1026                        if (DO_UPDATE)
1027                                sw->con_clear(vc_cons[currcons].d, y, 0, 1,
1028                                              x + 1);
1029                        break;
1030                case 2: /* erase whole line */
1031                        start = (unsigned short *) (pos - (x<<1));
1032                        count = video_num_columns;
1033                        if (DO_UPDATE)
1034                                sw->con_clear(vc_cons[currcons].d, y, 0, 1,
1035                                              video_num_columns);
1036                        break;
1037                default:
1038                        return;
1039        }
1040        scr_memsetw(start, video_erase_char, 2 * count);
1041        need_wrap = 0;
1042}
1043
1044static void csi_X(int currcons, int vpar) /* erase the following vpar positions */
1045{                                         /* not vt100? */
1046        int count;
1047
1048        if (!vpar)
1049                vpar++;
1050        count = (vpar > video_num_columns-x) ? (video_num_columns-x) : vpar;
1051
1052        scr_memsetw((unsigned short *) pos, video_erase_char, 2 * count);
1053        if (DO_UPDATE)
1054                sw->con_clear(vc_cons[currcons].d, y, x, 1, count);
1055        need_wrap = 0;
1056}
1057
1058static void default_attr(int currcons)
1059{
1060        intensity = 1;
1061        underline = 0;
1062        reverse = 0;
1063        blink = 0;
1064        color = def_color;
1065}
1066
1067/* console_sem is held */
1068static void csi_m(int currcons)
1069{
1070        int i;
1071
1072        for (i=0;i<=npar;i++)
1073                switch (par[i]) {
1074                        case 0: /* all attributes off */
1075                                default_attr(currcons);
1076                                break;
1077                        case 1:
1078                                intensity = 2;
1079                                break;
1080                        case 2:
1081                                intensity = 0;
1082                                break;
1083                        case 4:
1084                                underline = 1;
1085                                break;
1086                        case 5:
1087                                blink = 1;
1088                                break;
1089                        case 7:
1090                                reverse = 1;
1091                                break;
1092                        case 10: /* ANSI X3.64-1979 (SCO-ish?)
1093                                  * Select primary font, don't display
1094                                  * control chars if defined, don't set
1095                                  * bit 8 on output.
1096                                  */
1097                                translate = set_translate(charset == 0
1098                                                ? G0_charset
1099                                                : G1_charset,currcons);
1100                                disp_ctrl = 0;
1101                                toggle_meta = 0;
1102                                break;
1103                        case 11: /* ANSI X3.64-1979 (SCO-ish?)
1104                                  * Select first alternate font, lets
1105                                  * chars < 32 be displayed as ROM chars.
1106                                  */
1107                                translate = set_translate(IBMPC_MAP,currcons);
1108                                disp_ctrl = 1;
1109                                toggle_meta = 0;
1110                                break;
1111                        case 12: /* ANSI X3.64-1979 (SCO-ish?)
1112                                  * Select second alternate font, toggle
1113                                  * high bit before displaying as ROM char.
1114                                  */
1115                                translate = set_translate(IBMPC_MAP,currcons);
1116                                disp_ctrl = 1;
1117                                toggle_meta = 1;
1118                                break;
1119                        case 21:
1120                        case 22:
1121                                intensity = 1;
1122                                break;
1123                        case 24:
1124                                underline = 0;
1125                                break;
1126                        case 25:
1127                                blink = 0;
1128                                break;
1129                        case 27:
1130                                reverse = 0;
1131                                break;
1132                        case 38: /* ANSI X3.64-1979 (SCO-ish?)
1133                                  * Enables underscore, white foreground
1134                                  * with white underscore (Linux - use
1135                                  * default foreground).
1136                                  */
1137                                color = (def_color & 0x0f) | background;
1138                                underline = 1;
1139                                break;
1140                        case 39: /* ANSI X3.64-1979 (SCO-ish?)
1141                                  * Disable underline option.
1142                                  * Reset colour to default? It did this
1143                                  * before...
1144                                  */
1145                                color = (def_color & 0x0f) | background;
1146                                underline = 0;
1147                                break;
1148                        case 49:
1149                                color = (def_color & 0xf0) | foreground;
1150                                break;
1151                        default:
1152                                if (par[i] >= 30 && par[i] <= 37)
1153                                        color = color_table[par[i]-30]
1154                                                | background;
1155                                else if (par[i] >= 40 && par[i] <= 47)
1156                                        color = (color_table[par[i]-40]<<4)
1157                                                | foreground;
1158                                break;
1159                }
1160        update_attr(currcons);
1161}
1162
1163static void respond_string(const char * p, struct tty_struct * tty)
1164{
1165        while (*p) {
1166                tty_insert_flip_char(tty, *p, 0);
1167                p++;
1168        }
1169        con_schedule_flip(tty);
1170}
1171
1172static void cursor_report(int currcons, struct tty_struct * tty)
1173{
1174        char buf[40];
1175
1176        sprintf(buf, "\033[%d;%dR", y + (decom ? top+1 : 1), x+1);
1177        respond_string(buf, tty);
1178}
1179
1180static inline void status_report(struct tty_struct * tty)
1181{
1182        respond_string("\033[0n", tty); /* Terminal ok */
1183}
1184
1185static inline void respond_ID(struct tty_struct * tty)
1186{
1187        respond_string(VT102ID, tty);
1188}
1189
1190void mouse_report(struct tty_struct * tty, int butt, int mrx, int mry)
1191{
1192        char buf[8];
1193
1194        sprintf(buf, "\033[M%c%c%c", (char)(' ' + butt), (char)('!' + mrx),
1195                (char)('!' + mry));
1196        respond_string(buf, tty);
1197}
1198
1199/* invoked via ioctl(TIOCLINUX) and through set_selection */
1200int mouse_reporting(void)
1201{
1202        int currcons = fg_console;
1203
1204        return report_mouse;
1205}
1206
1207/* console_sem is held */
1208static void set_mode(int currcons, int on_off)
1209{
1210        int i;
1211
1212        for (i=0; i<=npar; i++)
1213                if (ques) switch(par[i]) {      /* DEC private modes set/reset */
1214                        case 1:                 /* Cursor keys send ^[Ox/^[[x */
1215                                if (on_off)
1216                                        set_kbd(decckm);
1217                                else
1218                                        clr_kbd(decckm);
1219                                break;
1220                        case 3: /* 80/132 mode switch unimplemented */
1221                                deccolm = on_off;
1222#if 0
1223                                (void) vc_resize(video_num_lines, deccolm ? 132 : 80);
1224                                /* this alone does not suffice; some user mode
1225                                   utility has to change the hardware regs */
1226#endif
1227                                break;
1228                        case 5:                 /* Inverted screen on/off */
1229                                if (decscnm != on_off) {
1230                                        decscnm = on_off;
1231                                        invert_screen(currcons, 0, screenbuf_size, 0);
1232                                        update_attr(currcons);
1233                                }
1234                                break;
1235                        case 6:                 /* Origin relative/absolute */
1236                                decom = on_off;
1237                                gotoxay(currcons,0,0);
1238                                break;
1239                        case 7:                 /* Autowrap on/off */
1240                                decawm = on_off;
1241                                break;
1242                        case 8:                 /* Autorepeat on/off */
1243                                if (on_off)
1244                                        set_kbd(decarm);
1245                                else
1246                                        clr_kbd(decarm);
1247                                break;
1248                        case 9:
1249                                report_mouse = on_off ? 1 : 0;
1250                                break;
1251                        case 25:                /* Cursor on/off */
1252                                deccm = on_off;
1253                                break;
1254                        case 1000:
1255                                report_mouse = on_off ? 2 : 0;
1256                                break;
1257                } else switch(par[i]) {         /* ANSI modes set/reset */
1258                        case 3:                 /* Monitor (display ctrls) */
1259                                disp_ctrl = on_off;
1260                                break;
1261                        case 4:                 /* Insert Mode on/off */
1262                                decim = on_off;
1263                                break;
1264                        case 20:                /* Lf, Enter == CrLf/Lf */
1265                                if (on_off)
1266                                        set_kbd(lnm);
1267                                else
1268                                        clr_kbd(lnm);
1269                                break;
1270                }
1271}
1272
1273/* console_sem is held */
1274static void setterm_command(int currcons)
1275{
1276        switch(par[0]) {
1277                case 1: /* set color for underline mode */
1278                        if (can_do_color && par[1] < 16) {
1279                                ulcolor = color_table[par[1]];
1280                                if (underline)
1281                                        update_attr(currcons);
1282                        }
1283                        break;
1284                case 2: /* set color for half intensity mode */
1285                        if (can_do_color && par[1] < 16) {
1286                                halfcolor = color_table[par[1]];
1287                                if (intensity == 0)
1288                                        update_attr(currcons);
1289                        }
1290                        break;
1291                case 8: /* store colors as defaults */
1292                        def_color = attr;
1293                        if (hi_font_mask == 0x100)
1294                                def_color >>= 1;
1295                        default_attr(currcons);
1296                        update_attr(currcons);
1297                        break;
1298                case 9: /* set blanking interval */
1299                        blankinterval = ((par[1] < 60) ? par[1] : 60) * 60 * HZ;
1300                        poke_blanked_console();
1301                        break;
1302                case 10: /* set bell frequency in Hz */
1303                        if (npar >= 1)
1304                                bell_pitch = par[1];
1305                        else
1306                                bell_pitch = DEFAULT_BELL_PITCH;
1307                        break;
1308                case 11: /* set bell duration in msec */
1309                        if (npar >= 1)
1310                                bell_duration = (par[1] < 2000) ?
1311                                        par[1]*HZ/1000 : 0;
1312                        else
1313                                bell_duration = DEFAULT_BELL_DURATION;
1314                        break;
1315                case 12: /* bring specified console to the front */
1316                        if (par[1] >= 1 && vc_cons_allocated(par[1]-1))
1317                                set_console(par[1] - 1);
1318                        break;
1319                case 13: /* unblank the screen */
1320                        poke_blanked_console();
1321                        break;
1322                case 14: /* set vesa powerdown interval */
1323                        vesa_off_interval = ((par[1] < 60) ? par[1] : 60) * 60 * HZ;
1324                        break;
1325        }
1326}
1327
1328/* console_sem is held */
1329static void csi_at(int currcons, unsigned int nr)
1330{
1331        if (nr > video_num_columns - x)
1332                nr = video_num_columns - x;
1333        else if (!nr)
1334                nr = 1;
1335        insert_char(currcons, nr);
1336}
1337
1338/* console_sem is held */
1339static void csi_L(int currcons, unsigned int nr)
1340{
1341        if (nr > video_num_lines - y)
1342                nr = video_num_lines - y;
1343        else if (!nr)
1344                nr = 1;
1345        scrdown(currcons,y,bottom,nr);
1346        need_wrap = 0;
1347}
1348
1349/* console_sem is held */
1350static void csi_P(int currcons, unsigned int nr)
1351{
1352        if (nr > video_num_columns - x)
1353                nr = video_num_columns - x;
1354        else if (!nr)
1355                nr = 1;
1356        delete_char(currcons, nr);
1357}
1358
1359/* console_sem is held */
1360static void csi_M(int currcons, unsigned int nr)
1361{
1362        if (nr > video_num_lines - y)
1363                nr = video_num_lines - y;
1364        else if (!nr)
1365                nr=1;
1366        scrup(currcons,y,bottom,nr);
1367        need_wrap = 0;
1368}
1369
1370/* console_sem is held (except via vc_init->reset_terminal */
1371static void save_cur(int currcons)
1372{
1373        saved_x         = x;
1374        saved_y         = y;
1375        s_intensity     = intensity;
1376        s_underline     = underline;
1377        s_blink         = blink;
1378        s_reverse       = reverse;
1379        s_charset       = charset;
1380        s_color         = color;
1381        saved_G0        = G0_charset;
1382        saved_G1        = G1_charset;
1383}
1384
1385/* console_sem is held */
1386static void restore_cur(int currcons)
1387{
1388        gotoxy(currcons,saved_x,saved_y);
1389        intensity       = s_intensity;
1390        underline       = s_underline;
1391        blink           = s_blink;
1392        reverse         = s_reverse;
1393        charset         = s_charset;
1394        color           = s_color;
1395        G0_charset      = saved_G0;
1396        G1_charset      = saved_G1;
1397        translate       = set_translate(charset ? G1_charset : G0_charset,currcons);
1398        update_attr(currcons);
1399        need_wrap = 0;
1400}
1401
1402enum { ESnormal, ESesc, ESsquare, ESgetpars, ESgotpars, ESfunckey,
1403        EShash, ESsetG0, ESsetG1, ESpercent, ESignore, ESnonstd,
1404        ESpalette };
1405
1406/* console_sem is held (except via vc_init()) */
1407static void reset_terminal(int currcons, int do_clear)
1408{
1409        top             = 0;
1410        bottom          = video_num_lines;
1411        vc_state        = ESnormal;
1412        ques            = 0;
1413        translate       = set_translate(LAT1_MAP,currcons);
1414        G0_charset      = LAT1_MAP;
1415        G1_charset      = GRAF_MAP;
1416        charset         = 0;
1417        need_wrap       = 0;
1418        report_mouse    = 0;
1419        utf             = 0;
1420        utf_count       = 0;
1421
1422        disp_ctrl       = 0;
1423        toggle_meta     = 0;
1424
1425        decscnm         = 0;
1426        decom           = 0;
1427        decawm          = 1;
1428        deccm           = 1;
1429        decim           = 0;
1430
1431        set_kbd(decarm);
1432        clr_kbd(decckm);
1433        clr_kbd(kbdapplic);
1434        clr_kbd(lnm);
1435        kbd_table[currcons].lockstate = 0;
1436        kbd_table[currcons].slockstate = 0;
1437        kbd_table[currcons].ledmode = LED_SHOW_FLAGS;
1438        kbd_table[currcons].ledflagstate = kbd_table[currcons].default_ledflagstate;
1439        
1440        /* Only schedule the keyboard_tasklet if it is enabled. */
1441        if(!atomic_read(&keyboard_tasklet.count))
1442                set_leds();
1443
1444        cursor_type = CUR_DEFAULT;
1445        complement_mask = s_complement_mask;
1446
1447        default_attr(currcons);
1448        update_attr(currcons);
1449
1450        tab_stop[0]     = 0x01010100;
1451        tab_stop[1]     =
1452        tab_stop[2]     =
1453        tab_stop[3]     =
1454        tab_stop[4]     = 0x01010101;
1455
1456        bell_pitch = DEFAULT_BELL_PITCH;
1457        bell_duration = DEFAULT_BELL_DURATION;
1458
1459        gotoxy(currcons,0,0);
1460        save_cur(currcons);
1461        if (do_clear)
1462            csi_J(currcons,2);
1463}
1464
1465/* console_sem is held */
1466static void do_con_trol(struct tty_struct *tty, unsigned int currcons, int c)
1467{
1468        /*
1469         *  Control characters can be used in the _middle_
1470         *  of an escape sequence.
1471         */
1472        switch (c) {
1473        case 0:
1474                return;
1475        case 7:
1476                if (bell_duration)
1477                        kd_mksound(bell_pitch, bell_duration);
1478                return;
1479        case 8:
1480                bs(currcons);
1481                return;
1482        case 9:
1483                pos -= (x << 1);
1484                while (x < video_num_columns - 1) {
1485                        x++;
1486                        if (tab_stop[x >> 5] & (1 << (x & 31)))
1487                                break;
1488                }
1489                pos += (x << 1);
1490                return;
1491        case 10: case 11: case 12:
1492                lf(currcons);
1493                if (!is_kbd(lnm))
1494                        return;
1495        case 13:
1496                cr(currcons);
1497                return;
1498        case 14:
1499                charset = 1;
1500                translate = set_translate(G1_charset,currcons);
1501                disp_ctrl = 1;
1502                return;
1503        case 15:
1504                charset = 0;
1505                translate = set_translate(G0_charset,currcons);
1506                disp_ctrl = 0;
1507                return;
1508        case 24: case 26:
1509                vc_state = ESnormal;
1510                return;
1511        case 27:
1512                vc_state = ESesc;
1513                return;
1514        case 127:
1515                del(currcons);
1516                return;
1517        case 128+27:
1518                vc_state = ESsquare;
1519                return;
1520        }
1521        switch(vc_state) {
1522        case ESesc:
1523                vc_state = ESnormal;
1524                switch (c) {
1525                case '[':
1526                        vc_state = ESsquare;
1527                        return;
1528                case ']':
1529                        vc_state = ESnonstd;
1530                        return;
1531                case '%':
1532                        vc_state = ESpercent;
1533                        return;
1534                case 'E':
1535                        cr(currcons);
1536                        lf(currcons);
1537                        return;
1538                case 'M':
1539                        ri(currcons);
1540                        return;
1541                case 'D':
1542                        lf(currcons);
1543                        return;
1544                case 'H':
1545                        tab_stop[x >> 5] |= (1 << (x & 31));
1546                        return;
1547                case 'Z':
1548                        respond_ID(tty);
1549                        return;
1550                case '7':
1551                        save_cur(currcons);
1552                        return;
1553                case '8':
1554                        restore_cur(currcons);
1555                        return;
1556                case '(':
1557                        vc_state = ESsetG0;
1558                        return;
1559                case ')':
1560                        vc_state = ESsetG1;
1561                        return;
1562                case '#':
1563                        vc_state = EShash;
1564                        return;
1565                case 'c':
1566                        reset_terminal(currcons,1);
1567                        return;
1568                case '>':  /* Numeric keypad */
1569                        clr_kbd(kbdapplic);
1570                        return;
1571                case '=':  /* Appl. keypad */
1572                        set_kbd(kbdapplic);
1573                        return;
1574                }
1575                return;
1576        case ESnonstd:
1577                if (c=='P') {   /* palette escape sequence */
1578                        for (npar=0; npar<NPAR; npar++)
1579                                par[npar] = 0 ;
1580                        npar = 0 ;
1581                        vc_state = ESpalette;
1582                        return;
1583                } else if (c=='R') {   /* reset palette */
1584                        reset_palette(currcons);
1585                        vc_state = ESnormal;
1586                } else
1587                        vc_state = ESnormal;
1588                return;
1589        case ESpalette:
1590                if ( (c>='0'&&c<='9') || (c>='A'&&c<='F') || (c>='a'&&c<='f') ) {
1591                        par[npar++] = (c>'9' ? (c&0xDF)-'A'+10 : c-'0') ;
1592                        if (npar==7) {
1593                                int i = par[0]*3, j = 1;
1594                                palette[i] = 16*par[j++];
1595                                palette[i++] += par[j++];
1596                                palette[i] = 16*par[j++];
1597                                palette[i++] += par[j++];
1598                                palette[i] = 16*par[j++];
1599                                palette[i] += par[j];
1600                                set_palette(currcons);
1601                                vc_state = ESnormal;
1602                        }
1603                } else
1604                        vc_state = ESnormal;
1605                return;
1606        case ESsquare:
1607                for(npar = 0 ; npar < NPAR ; npar++)
1608                        par[npar] = 0;
1609                npar = 0;
1610                vc_state = ESgetpars;
1611                if (c == '[') { /* Function key */
1612                        vc_state=ESfunckey;
1613                        return;
1614                }
1615                ques = (c=='?');
1616                if (ques)
1617                        return;
1618        case ESgetpars:
1619                if (c==';' && npar<NPAR-1) {
1620                        npar++;
1621                        return;
1622                } else if (c>='0' && c<='9') {
1623                        par[npar] *= 10;
1624                        par[npar] += c-'0';
1625                        return;
1626                } else vc_state=ESgotpars;
1627        case ESgotpars:
1628                vc_state = ESnormal;
1629                switch(c) {
1630                case 'h':
1631                        set_mode(currcons,1);
1632                        return;
1633                case 'l':
1634                        set_mode(currcons,0);
1635                        return;
1636                case 'c':
1637                        if (ques) {
1638                                if (par[0])
1639                                        cursor_type = par[0] | (par[1]<<8) | (par[2]<<16);
1640                                else
1641                                        cursor_type = CUR_DEFAULT;
1642                                return;
1643                        }
1644                        break;
1645                case 'm':
1646                        if (ques) {
1647                                clear_selection();
1648                                if (par[0])
1649                                        complement_mask = par[0]<<8 | par[1];
1650                                else
1651                                        complement_mask = s_complement_mask;
1652                                return;
1653                        }
1654                        break;
1655                case 'n':
1656                        if (!ques) {
1657                                if (par[0] == 5)
1658                                        status_report(tty);
1659                                else if (par[0] == 6)
1660                                        cursor_report(currcons,tty);
1661                        }
1662                        return;
1663                }
1664                if (ques) {
1665                        ques = 0;
1666                        return;
1667                }
1668                switch(c) {
1669                case 'G': case '`':
1670                        if (par[0]) par[0]--;
1671                        gotoxy(currcons,par[0],y);
1672                        return;
1673                case 'A':
1674                        if (!par[0]) par[0]++;
1675                        gotoxy(currcons,x,y-par[0]);
1676                        return;
1677                case 'B': case 'e':
1678                        if (!par[0]) par[0]++;
1679                        gotoxy(currcons,x,y+par[0]);
1680                        return;
1681                case 'C': case 'a':
1682                        if (!par[0]) par[0]++;
1683                        gotoxy(currcons,x+par[0],y);
1684                        return;
1685                case 'D':
1686                        if (!par[0]) par[0]++;
1687                        gotoxy(currcons,x-par[0],y);
1688                        return;
1689                case 'E':
1690                        if (!par[0]) par[0]++;
1691                        gotoxy(currcons,0,y+par[0]);
1692                        return;
1693                case 'F':
1694                        if (!par[0]) par[0]++;
1695                        gotoxy(currcons,0,y-par[0]);
1696                        return;
1697                case 'd':
1698                        if (par[0]) par[0]--;
1699                        gotoxay(currcons,x,par[0]);
1700                        return;
1701                case 'H': case 'f':
1702                        if (par[0]) par[0]--;
1703                        if (par[1]) par[1]--;
1704                        gotoxay(currcons,par[1],par[0]);
1705                        return;
1706                case 'J':
1707                        csi_J(currcons,par[0]);
1708                        return;
1709                case 'K':
1710                        csi_K(currcons,par[0]);
1711                        return;
1712                case 'L':
1713                        csi_L(currcons,par[0]);
1714                        return;
1715                case 'M':
1716                        csi_M(currcons,par[0]);
1717                        return;
1718                case 'P':
1719                        csi_P(currcons,par[0]);
1720                        return;
1721                case 'c':
1722                        if (!par[0])
1723                                respond_ID(tty);
1724                        return;
1725                case 'g':
1726                        if (!par[0])
1727                                tab_stop[x >> 5] &= ~(1 << (x & 31));
1728                        else if (par[0] == 3) {
1729                                tab_stop[0] =
1730                                        tab_stop[1] =
1731                                        tab_stop[2] =
1732                                        tab_stop[3] =
1733                                        tab_stop[4] = 0;
1734                        }
1735                        return;
1736                case 'm':
1737                        csi_m(currcons);
1738                        return;
1739                case 'q': /* DECLL - but only 3 leds */
1740                        /* map 0,1,2,3 to 0,1,2,4 */
1741                        if (par[0] < 4)
1742                                setledstate(kbd_table + currcons,
1743                                            (par[0] < 3) ? par[0] : 4);
1744                        return;
1745                case 'r':
1746                        if (!par[0])
1747                                par[0]++;
1748                        if (!par[1])
1749                                par[1] = video_num_lines;
1750                        /* Minimum allowed region is 2 lines */
1751                        if (par[0] < par[1] &&
1752                            par[1] <= video_num_lines) {
1753                                top=par[0]-1;
1754                                bottom=par[1];
1755                                gotoxay(currcons,0,0);
1756                        }
1757                        return;
1758                case 's':
1759                        save_cur(currcons);
1760                        return;
1761                case 'u':
1762                        restore_cur(currcons);
1763                        return;
1764                case 'X':
1765                        csi_X(currcons, par[0]);
1766                        return;
1767                case '@':
1768                        csi_at(currcons,par[0]);
1769                        return;
1770                case ']': /* setterm functions */
1771                        setterm_command(currcons);
1772                        return;
1773                }
1774                return;
1775        case ESpercent:
1776                vc_state = ESnormal;
1777                switch (c) {
1778                case '@':  /* defined in ISO 2022 */
1779                        utf = 0;
1780                        return;
1781                case 'G':  /* prelim official escape code */
1782                case '8':  /* retained for compatibility */
1783                        utf = 1;
1784                        return;
1785                }
1786                return;
1787        case ESfunckey:
1788                vc_state = ESnormal;
1789                return;
1790        case EShash:
1791                vc_state = ESnormal;
1792                if (c == '8') {
1793                        /* DEC screen alignment test. kludge :-) */
1794                        video_erase_char =
1795                                (video_erase_char & 0xff00) | 'E';
1796                        csi_J(currcons, 2);
1797                        video_erase_char =
1798                                (video_erase_char & 0xff00) | ' ';
1799                        do_update_region(currcons, origin, screenbuf_size/2);
1800                }
1801                return;
1802        case ESsetG0:
1803                if (c == '0')
1804                        G0_charset = GRAF_MAP;
1805                else if (c == 'B')
1806                        G0_charset = LAT1_MAP;
1807                else if (c == 'U')
1808                        G0_charset = IBMPC_MAP;
1809                else if (c == 'K')
1810                        G0_charset = USER_MAP;
1811                if (charset == 0)
1812                        translate = set_translate(G0_charset,currcons);
1813                vc_state = ESnormal;
1814                return;
1815        case ESsetG1:
1816                if (c == '0')
1817                        G1_charset = GRAF_MAP;
1818                else if (c == 'B')
1819                        G1_charset = LAT1_MAP;
1820                else if (c == 'U')
1821                        G1_charset = IBMPC_MAP;
1822                else if (c == 'K')
1823                        G1_charset = USER_MAP;
1824                if (charset == 1)
1825                        translate = set_translate(G1_charset,currcons);
1826                vc_state = ESnormal;
1827                return;
1828        default:
1829                vc_state = ESnormal;
1830        }
1831}
1832
1833/* This is a temporary buffer used to prepare a tty console write
1834 * so that we can easily avoid touching user space while holding the
1835 * console spinlock.  It is allocated in con_init and is shared by
1836 * this code and the vc_screen read/write tty calls.
1837 *
1838 * We have to allocate this statically in the kernel data section
1839 * since console_init (and thus con_init) are called before any
1840 * kernel memory allocation is available.
1841 */
1842char con_buf[PAGE_SIZE];
1843#define CON_BUF_SIZE    PAGE_SIZE
1844DECLARE_MUTEX(con_buf_sem);
1845
1846/* acquires console_sem */
1847static int do_con_write(struct tty_struct * tty, int from_user,
1848                        const unsigned char *buf, int count)
1849{
1850#ifdef VT_BUF_VRAM_ONLY
1851#define FLUSH do { } while(0);
1852#else
1853#define FLUSH if (draw_x >= 0) { \
1854        sw->con_putcs(vc_cons[currcons].d, (u16 *)draw_from, (u16 *)draw_to-(u16 *)draw_from, y, draw_x); \
1855        draw_x = -1; \
1856        }
1857#endif
1858
1859        int c, tc, ok, n = 0, draw_x = -1;
1860        unsigned int currcons;
1861        unsigned long draw_from = 0, draw_to = 0;
1862        struct vt_struct *vt = (struct vt_struct *)tty->driver_data;
1863        u16 himask, charmask;
1864        const unsigned char *orig_buf = NULL;
1865        int orig_count;
1866
1867        if (in_interrupt())
1868                return count;
1869                
1870        currcons = vt->vc_num;
1871        if (!vc_cons_allocated(currcons)) {
1872            /* could this happen? */
1873            static int error = 0;
1874            if (!error) {
1875                error = 1;
1876                printk("con_write: tty %d not allocated\n", currcons+1);
1877            }
1878            return 0;
1879        }
1880
1881        orig_buf = buf;
1882        orig_count = count;
1883
1884        if (from_user) {
1885                down(&con_buf_sem);
1886
1887again:
1888                if (count > CON_BUF_SIZE)
1889                        count = CON_BUF_SIZE;
1890                console_conditional_schedule();
1891                if (copy_from_user(con_buf, buf, count)) {
1892                        n = 0; /* ?? are error codes legal here ?? */
1893                        goto out;
1894                }
1895
1896                buf = con_buf;
1897        }
1898
1899        /* At this point 'buf' is guarenteed to be a kernel buffer
1900         * and therefore no access to userspace (and therefore sleeping)
1901         * will be needed.  The con_buf_sem serializes all tty based
1902         * console rendering and vcs write/read operations.  We hold
1903         * the console spinlock during the entire write.
1904         */
1905
1906        acquire_console_sem();
1907
1908        himask = hi_font_mask;
1909        charmask = himask ? 0x1ff : 0xff;
1910
1911        /* undraw cursor first */
1912        if (IS_FG)
1913                hide_cursor(currcons);
1914
1915        while (!tty->stopped && count) {
1916                c = *buf;
1917                buf++;
1918                n++;
1919                count--;
1920
1921                if (utf) {
1922                    /* Combine UTF-8 into Unicode */
1923                    /* Incomplete characters silently ignored */
1924                    if(c > 0x7f) {
1925                        if (utf_count > 0 && (c & 0xc0) == 0x80) {
1926                                utf_char = (utf_char << 6) | (c & 0x3f);
1927                                utf_count--;
1928                                if (utf_count == 0)
1929                                    tc = c = utf_char;
1930                                else continue;
1931                        } else {
1932                                if ((c & 0xe0) == 0xc0) {
1933                                    utf_count = 1;
1934                                    utf_char = (c & 0x1f);
1935                                } else if ((c & 0xf0) == 0xe0) {
1936                                    utf_count = 2;
1937                                    utf_char = (c & 0x0f);
1938                                } else if ((c & 0xf8) == 0xf0) {
1939                                    utf_count = 3;
1940                                    utf_char = (c & 0x07);
1941                                } else if ((c & 0xfc) == 0xf8) {
1942                                    utf_count = 4;
1943                                    utf_char = (c & 0x03);
1944                                } else if ((c & 0xfe) == 0xfc) {
1945                                    utf_count = 5;
1946                                    utf_char = (c & 0x01);
1947                                } else
1948                                    utf_count = 0;
1949                                continue;
1950                              }
1951                    } else {
1952                      tc = c;
1953                      utf_count = 0;
1954                    }
1955                } else {        /* no utf */
1956                  tc = translate[toggle_meta ? (c|0x80) : c];
1957                }
1958
1959                /* If the original code was a control character we
1960                 * only allow a glyph to be displayed if the code is
1961                 * not normally used (such as for cursor movement) or
1962                 * if the disp_ctrl mode has been explicitly enabled.
1963                 * Certain characters (as given by the CTRL_ALWAYS
1964                 * bitmap) are always displayed as control characters,
1965                 * as the console would be pretty useless without
1966                 * them; to display an arbitrary font position use the
1967                 * direct-to-font zone in UTF-8 mode.
1968                 */
1969                ok = tc && (c >= 32 ||
1970                            (!utf && !(((disp_ctrl ? CTRL_ALWAYS
1971                                         : CTRL_ACTION) >> c) & 1)))
1972                        && (c != 127 || disp_ctrl)
1973                        && (c != 128+27);
1974
1975                if (vc_state == ESnormal && ok) {
1976                        /* Now try to find out how to display it */
1977                        tc = conv_uni_to_pc(vc_cons[currcons].d, tc);
1978                        if ( tc == -4 ) {
1979                                /* If we got -4 (not found) then see if we have
1980                                   defined a replacement character (U+FFFD) */
1981                                tc = conv_uni_to_pc(vc_cons[currcons].d, 0xfffd);
1982
1983                                /* One reason for the -4 can be that we just
1984                                   did a clear_unimap();
1985                                   try at least to show something. */
1986                                if (tc == -4)
1987                                     tc = c;
1988                        } else if ( tc == -3 ) {
1989                                /* Bad hash table -- hope for the best */
1990                                tc = c;
1991                        }
1992                        if (tc & ~charmask)
1993                                continue; /* Conversion failed */
1994
1995                        if (need_wrap || decim)
1996                                FLUSH
1997                        if (need_wrap) {
1998                                cr(currcons);
1999                                lf(currcons);
2000                        }
2001                        if (decim)
2002                                insert_char(currcons, 1);
2003                        scr_writew(himask ?
2004                                     ((attr << 8) & ~himask) + ((tc & 0x100) ? himask : 0) + (tc & 0xff) :
2005                                     (attr << 8) + tc,
2006                                   (u16 *) pos);
2007                        if (DO_UPDATE && draw_x < 0) {
2008                                draw_x = x;
2009                                draw_from = pos;
2010                        }
2011                        if (x == video_num_columns - 1) {
2012                                need_wrap = decawm;
2013                                draw_to = pos+2;
2014                        } else {
2015                                x++;
2016                                draw_to = (pos+=2);
2017                        }
2018                        continue;
2019                }
2020                FLUSH
2021                do_con_trol(tty, currcons, c);
2022        }
2023        FLUSH
2024        console_conditional_schedule();
2025        release_console_sem();
2026
2027out:
2028        if (from_user) {
2029                /* If the user requested something larger than
2030                 * the CON_BUF_SIZE, and the tty is not stopped,
2031                 * keep going.
2032                 */
2033                if ((orig_count > CON_BUF_SIZE) && !tty->stopped) {
2034                        orig_count -= CON_BUF_SIZE;
2035                        orig_buf += CON_BUF_SIZE;
2036                        count = orig_count;
2037                        buf = orig_buf;
2038                        goto again;
2039                }
2040
2041                up(&con_buf_sem);
2042        }
2043
2044        return n;
2045#undef FLUSH
2046}
2047
2048/*
2049 * This is the console switching callback.
2050 *
2051 * Doing console switching in a process context allows
2052 * us to do the switches asynchronously (needed when we want
2053 * to switch due to a keyboard interrupt).  Synchronization
2054 * with other console code and prevention of re-entrancy is
2055 * ensured with console_sem.
2056 */
2057static void console_callback(void *unused) 
2058{
2059        acquire_console_sem();
2060        __console_callback(); 
2061        release_console_sem();  
2062} 
2063
2064static void __console_callback(void)
2065{
2066        if (want_console >= 0) {
2067                if (want_console != fg_console && vc_cons_allocated(want_console)) {
2068                        hide_cursor(fg_console);
2069                        change_console(want_console);
2070                        /* we only changed when the console had already
2071                           been allocated - a new console is not created
2072                           in an interrupt routine */
2073                }
2074                want_console = -1;
2075        }
2076        if (do_poke_blanked_console) { /* do not unblank for a LED change */
2077                do_poke_blanked_console = 0;
2078                poke_blanked_console();
2079        }
2080        if (scrollback_delta) {
2081                int currcons = fg_console;
2082                clear_selection();
2083                if (vcmode == KD_TEXT)
2084                        sw->con_scrolldelta(vc_cons[currcons].d, scrollback_delta);
2085                scrollback_delta = 0;
2086        }
2087}
2088
2089void set_console(int nr)
2090{
2091        want_console = nr;
2092        schedule_console_callback();
2093}
2094
2095#ifdef CONFIG_VT_CONSOLE
2096
2097/*
2098 *      Console on virtual terminal
2099 *
2100 * The console must be locked when we get here.
2101 */
2102
2103void vt_console_print(struct console *co, const char * b, unsigned count)
2104{
2105        int currcons = fg_console;
2106        unsigned char c;
2107        static unsigned long printing;
2108        const ushort *start;
2109        ushort cnt = 0;
2110        ushort myx;
2111
2112        /* console busy or not yet initialized */
2113        if (!printable || test_and_set_bit(0, &printing))
2114                return;
2115
2116        pm_access(pm_con);
2117
2118        if (kmsg_redirect && vc_cons_allocated(kmsg_redirect - 1))
2119                currcons = kmsg_redirect - 1;
2120
2121        /* read `x' only after setting currecons properly (otherwise
2122           the `x' macro will read the x of the foreground console). */
2123        myx = x;
2124
2125        if (!vc_cons_allocated(currcons)) {
2126                /* impossible */
2127                /* printk("vt_console_print: tty %d not allocated ??\n", currcons+1); */
2128                goto quit;
2129        }
2130
2131        if (vcmode != KD_TEXT)
2132                goto quit;
2133
2134        /* undraw cursor first */
2135        if (IS_FG)
2136                hide_cursor(currcons);
2137
2138        start = (ushort *)pos;
2139
2140        /* Contrived structure to try to emulate original need_wrap behaviour
2141         * Problems caused when we have need_wrap set on '\n' character */
2142        while (count--) {
2143                c = *b++;
2144                if (c == 10 || c == 13 || c == 8 || need_wrap) {
2145                        if (cnt > 0) {
2146                                if (IS_VISIBLE)
2147                                        sw->con_putcs(vc_cons[currcons].d, start, cnt, y, x);
2148                                x += cnt;
2149                                if (need_wrap)
2150                                        x--;
2151                                cnt = 0;
2152                        }
2153                        if (c == 8) {           /* backspace */
2154                                bs(currcons);
2155                                start = (ushort *)pos;
2156                                myx = x;
2157                                continue;
2158                        }
2159                        if (c != 13)
2160                                lf(currcons);
2161                        cr(currcons);
2162                        start = (ushort *)pos;
2163                        myx = x;
2164                        if (c == 10 || c == 13)
2165                                continue;
2166                }
2167                scr_writew((attr << 8) + c, (unsigned short *) pos);
2168                cnt++;
2169                if (myx == video_num_columns - 1) {
2170                        need_wrap = 1;
2171                        continue;
2172                }
2173                pos+=2;
2174                myx++;
2175        }
2176        if (cnt > 0) {
2177                if (IS_VISIBLE)
2178                        sw->con_putcs(vc_cons[currcons].d, start, cnt, y, x);
2179                x += cnt;
2180                if (x == video_num_columns) {
2181                        x--;
2182                        need_wrap = 1;
2183                }
2184        }
2185        set_cursor(currcons);
2186
2187        if (!oops_in_progress)
2188                poke_blanked_console();
2189
2190quit:
2191        clear_bit(0, &printing);
2192}
2193
2194static kdev_t vt_console_device(struct console *c)
2195{
2196        return MKDEV(TTY_MAJOR, c->index ? c->index : fg_console + 1);
2197}
2198
2199struct console vt_console_driver = {
2200        name:           "tty",
2201        write:          vt_console_print,
2202        device:         vt_console_device,
2203        unblank:        unblank_screen,
2204        flags:          CON_PRINTBUFFER,
2205        index:          -1,
2206};
2207#endif
2208
2209/*
2210 *      Handling of Linux-specific VC ioctls
2211 */
2212
2213/*
2214 * Generally a bit racy with respect to console_sem().
2215 *
2216 * There are some functions which don't need it.
2217 *
2218 * There are some functions which can sleep for arbitrary periods (paste_selection)
2219 * but we don't need the lock there anyway.
2220 *
2221 * set_selection has locking, and definitely needs it
2222 */
2223
2224int tioclinux(struct tty_struct *tty, unsigned long arg)
2225{
2226        char type, data;
2227        int ret;
2228
2229        if (tty->driver.type != TTY_DRIVER_TYPE_CONSOLE)
2230                return -EINVAL;
2231        if (current->tty != tty && !capable(CAP_SYS_ADMIN))
2232                return -EPERM;
2233        if (get_user(type, (char *)arg))
2234                return -EFAULT;
2235        ret = 0;
2236        switch (type)
2237        {
2238                case 2:
2239                        acquire_console_sem();
2240                        ret = set_selection(arg, tty, 1);
2241                        release_console_sem();
2242                        break;
2243                case 3:
2244                        ret = paste_selection(tty);
2245                        break;
2246                case 4:
2247                        unblank_screen();
2248                        break;
2249                case 5:
2250                        ret = sel_loadlut(arg);
2251                        break;
2252                case 6:
2253                        
2254        /*
2255         * Make it possible to react to Shift+Mousebutton.
2256         * Note that 'shift_state' is an undocumented
2257         * kernel-internal variable; programs not closely
2258         * related to the kernel should not use this.
2259         */
2260                        data = shift_state;
2261                        ret = __put_user(data, (char *) arg);
2262                        break;
2263                case 7:
2264                        data = mouse_reporting();
2265                        ret = __put_user(data, (char *) arg);
2266                        break;
2267                case 10:
2268                        set_vesa_blanking(arg);
2269                        break;;
2270                case 11:        /* set kmsg redirect */
2271                        if (!capable(CAP_SYS_ADMIN)) {
2272                                ret = -EPERM;
2273                        } else {
2274                                if (get_user(data, (char *)arg+1))
2275                                        ret = -EFAULT;
2276                                else
2277                                        kmsg_redirect = data;
2278                        }
2279                        break;
2280                case 12:        /* get fg_console */
2281                        ret = fg_console;
2282                        break;
2283                default:
2284                        ret = -EINVAL;
2285                        break;
2286        }
2287        return ret;
2288}
2289
2290/*
2291 *      /dev/ttyN handling
2292 */
2293
2294static int con_write(struct tty_struct * tty, int from_user,
2295                     const unsigned char *buf, int count)
2296{
2297        int     retval;
2298
2299        pm_access(pm_con);
2300        retval = do_con_write(tty, from_user, buf, count);
2301        con_flush_chars(tty);
2302
2303        return retval;
2304}
2305
2306static void con_put_char(struct tty_struct *tty, unsigned char ch)
2307{
2308        if (in_interrupt())
2309                return;         /* n_r3964 calls put_char() from interrupt context */
2310        pm_access(pm_con);
2311        do_con_write(tty, 0, &ch, 1);
2312}
2313
2314static int con_write_room(struct tty_struct *tty)
2315{
2316        if (tty->stopped)
2317                return 0;
2318        return 4096;            /* No limit, really; we're not buffering */
2319}
2320
2321static int con_chars_in_buffer(struct tty_struct *tty)
2322{
2323        return 0;               /* we're not buffering */
2324}
2325
2326/*
2327 * con_throttle and con_unthrottle are only used for
2328 * paste_selection(), which has to stuff in a large number of
2329 * characters...
2330 */
2331static void con_throttle(struct tty_struct *tty)
2332{
2333}
2334
2335static void con_unthrottle(struct tty_struct *tty)
2336{
2337        struct vt_struct *vt = (struct vt_struct *) tty->driver_data;
2338
2339        wake_up_interruptible(&vt->paste_wait);
2340}
2341
2342/*
2343 * Turn the Scroll-Lock LED on when the tty is stopped
2344 */
2345static void con_stop(struct tty_struct *tty)
2346{
2347        int console_num;
2348        if (!tty)
2349                return;
2350        console_num = MINOR(tty->device) - (tty->driver.minor_start);
2351        if (!vc_cons_allocated(console_num))
2352                return;
2353        set_vc_kbd_led(kbd_table + console_num, VC_SCROLLOCK);
2354        set_leds();
2355}
2356
2357/*
2358 * Turn the Scroll-Lock LED off when the console is started
2359 */
2360static void con_start(struct tty_struct *tty)
2361{
2362        int console_num;
2363        if (!tty)
2364                return;
2365        console_num = MINOR(tty->device) - (tty->driver.minor_start);
2366        if (!vc_cons_allocated(console_num))
2367                return;
2368        clr_vc_kbd_led(kbd_table + console_num, VC_SCROLLOCK);
2369        set_leds();
2370}
2371
2372/*
2373 * we can race here against con_close, so we grab the bkl
2374 * and check the pointer before calling set_cursor
2375 */
2376static void con_flush_chars(struct tty_struct *tty)
2377{
2378        struct vt_struct *vt;
2379
2380        if (in_interrupt())     /* from flush_to_ldisc */
2381                return;
2382
2383        pm_access(pm_con);
2384        lock_kernel();
2385        acquire_console_sem();
2386        vt = (struct vt_struct *)tty->driver_data;
2387        if (vt)
2388                set_cursor(vt->vc_num);
2389        release_console_sem();
2390        unlock_kernel();
2391}
2392
2393/*
2394 * Allocate the console screen memory.
2395 */
2396static int con_open(struct tty_struct *tty, struct file * filp)
2397{
2398        unsigned int    currcons;
2399        int i;
2400
2401        currcons = MINOR(tty->device) - tty->driver.minor_start;
2402
2403        i = vc_allocate(currcons);
2404        if (i)
2405                return i;
2406
2407        vt_cons[currcons]->vc_num = currcons;
2408        tty->driver_data = vt_cons[currcons];
2409
2410        if (!tty->winsize.ws_row && !tty->winsize.ws_col) {
2411                tty->winsize.ws_row = video_num_lines;
2412                tty->winsize.ws_col = video_num_columns;
2413        }
2414        if (tty->count == 1)
2415                vcs_make_devfs (currcons, 0);
2416        return 0;
2417}
2418
2419static void con_close(struct tty_struct *tty, struct file * filp)
2420{
2421        if (!tty)
2422                return;
2423        if (tty->count != 1) return;
2424        vcs_make_devfs (MINOR (tty->device) - tty->driver.minor_start, 1);
2425        tty->driver_data = 0;
2426}
2427
2428static void vc_init(unsigned int currcons, unsigned int rows, unsigned int cols, int do_clear)
2429{
2430        int j, k ;
2431
2432        video_num_columns = cols;
2433        video_num_lines = rows;
2434        video_size_row = cols<<1;
2435        screenbuf_size = video_num_lines * video_size_row;
2436
2437        set_origin(currcons);
2438        pos = origin;
2439        reset_vc(currcons);
2440        for (j=k=0; j<16; j++) {
2441                vc_cons[currcons].d->vc_palette[k++] = default_red[j] ;
2442                vc_cons[currcons].d->vc_palette[k++] = default_grn[j] ;
2443                vc_cons[currcons].d->vc_palette[k++] = default_blu[j] ;
2444        }
2445        def_color       = 0x07;   /* white */
2446        ulcolor         = 0x0f;   /* bold white */
2447        halfcolor       = 0x08;   /* grey */
2448        init_waitqueue_head(&vt_cons[currcons]->paste_wait);
2449        reset_terminal(currcons, do_clear);
2450}
2451
2452/*
2453 * This routine initializes console interrupts, and does nothing
2454 * else. If you want the screen to clear, call tty_write with
2455 * the appropriate escape-sequence.
2456 */
2457
2458struct tty_driver console_driver;
2459static int console_refcount;
2460
2461void __init con_init(void)
2462{
2463        const char *display_desc = NULL;
2464        unsigned int currcons = 0;
2465
2466        if (conswitchp)
2467                display_desc = conswitchp->con_startup();
2468        if (!display_desc) {
2469                fg_console = 0;
2470                return;
2471        }
2472
2473        memset(&console_driver, 0, sizeof(struct tty_driver));
2474        console_driver.magic = TTY_DRIVER_MAGIC;
2475        console_driver.name = "vc/%d";
2476        console_driver.name_base = 1;
2477        console_driver.major = TTY_MAJOR;
2478        console_driver.minor_start = 1;
2479        console_driver.num = MAX_NR_CONSOLES;
2480        console_driver.type = TTY_DRIVER_TYPE_CONSOLE;
2481        console_driver.init_termios = tty_std_termios;
2482        console_driver.flags = TTY_DRIVER_REAL_RAW | TTY_DRIVER_RESET_TERMIOS;
2483        /* Tell tty_register_driver() to skip consoles because they are
2484         * registered before kmalloc() is ready. We'll patch them in later. 
2485         * See comments at console_init(); see also con_init_devfs(). 
2486         */
2487        console_driver.flags |= TTY_DRIVER_NO_DEVFS;
2488        console_driver.refcount = &console_refcount;
2489        console_driver.table = console_table;
2490        console_driver.termios = console_termios;
2491        console_driver.termios_locked = console_termios_locked;
2492
2493        console_driver.open = con_open;
2494        console_driver.close = con_close;
2495        console_driver.write = con_write;
2496        console_driver.write_room = con_write_room;
2497        console_driver.put_char = con_put_char;
2498        console_driver.flush_chars = con_flush_chars;
2499        console_driver.chars_in_buffer = con_chars_in_buffer;
2500        console_driver.ioctl = vt_ioctl;
2501        console_driver.stop = con_stop;
2502        console_driver.start = con_start;
2503        console_driver.throttle = con_throttle;
2504        console_driver.unthrottle = con_unthrottle;
2505
2506        if (tty_register_driver(&console_driver))
2507                panic("Couldn't register console driver\n");
2508
2509        init_timer(&console_timer);
2510        console_timer.function = blank_screen;
2511        if (blankinterval) {
2512                mod_timer(&console_timer, jiffies + blankinterval);
2513        }
2514
2515        /*
2516         * kmalloc is not running yet - we use the bootmem allocator.
2517         */
2518        for (currcons = 0; currcons < MIN_NR_CONSOLES; currcons++) {
2519                vc_cons[currcons].d = (struct vc_data *)
2520                                alloc_bootmem(sizeof(struct vc_data));
2521                vt_cons[currcons] = (struct vt_struct *)
2522                                alloc_bootmem(sizeof(struct vt_struct));
2523                visual_init(currcons, 1);
2524                screenbuf = (unsigned short *) alloc_bootmem(screenbuf_size);
2525                kmalloced = 0;
2526                vc_init(currcons, video_num_lines, video_num_columns, 
2527                        currcons || !sw->con_save_screen);
2528        }
2529        currcons = fg_console = 0;
2530        master_display_fg = vc_cons[currcons].d;
2531        set_origin(currcons);
2532        save_screen(currcons);
2533        gotoxy(currcons,x,y);
2534        csi_J(currcons, 0);
2535        update_screen(fg_console);
2536        printk("Console: %s %s %dx%d",
2537                can_do_color ? "colour" : "mono",
2538                display_desc, video_num_columns, video_num_lines);
2539        printable = 1;
2540        printk("\n");
2541
2542#ifdef CONFIG_VT_CONSOLE
2543        register_console(&vt_console_driver);
2544#endif
2545}
2546
2547#ifndef VT_SINGLE_DRIVER
2548
2549static void clear_buffer_attributes(int currcons)
2550{
2551        unsigned short *p = (unsigned short *) origin;
2552        int count = screenbuf_size/2;
2553        int mask = hi_font_mask | 0xff;
2554
2555        for (; count > 0; count--, p++) {
2556                scr_writew((scr_readw(p)&mask) | (video_erase_char&~mask), p);
2557        }
2558}
2559
2560/*
2561 *      If we support more console drivers, this function is used
2562 *      when a driver wants to take over some existing consoles
2563 *      and become default driver for newly opened ones.
2564 */
2565
2566void take_over_console(const struct consw *csw, int first, int last, int deflt)
2567{
2568        int i, j = -1;
2569        const char *desc;
2570
2571        desc = csw->con_startup();
2572        if (!desc) return;
2573        if (deflt)
2574                conswitchp = csw;
2575
2576        for (i = first; i <= last; i++) {
2577                int old_was_color;
2578                int currcons = i;
2579
2580                con_driver_map[i] = csw;
2581
2582                if (!vc_cons[i].d || !vc_cons[i].d->vc_sw)
2583                        continue;
2584
2585                j = i;
2586                if (IS_VISIBLE)
2587                        save_screen(i);
2588                old_was_color = vc_cons[i].d->vc_can_do_color;
2589                vc_cons[i].d->vc_sw->con_deinit(vc_cons[i].d);
2590                visual_init(i, 0);
2591                update_attr(i);
2592
2593                /* If the console changed between mono <-> color, then
2594                 * the attributes in the screenbuf will be wrong.  The
2595                 * following resets all attributes to something sane.
2596                 */
2597                if (old_was_color != vc_cons[i].d->vc_can_do_color)
2598                        clear_buffer_attributes(i);
2599
2600                if (IS_VISIBLE)
2601                        update_screen(i);
2602        }
2603        printk("Console: switching ");
2604        if (!deflt)
2605                printk("consoles %d-%d ", first+1, last+1);
2606        if (j >= 0)
2607                printk("to %s %s %dx%d\n",
2608                       vc_cons[j].d->vc_can_do_color ? "colour" : "mono",
2609                       desc, vc_cons[j].d->vc_cols, vc_cons[j].d->vc_rows);
2610        else
2611                printk("to %s\n", desc);
2612}
2613
2614void give_up_console(const struct consw *csw)
2615{
2616        int i;
2617
2618        for(i = 0; i < MAX_NR_CONSOLES; i++)
2619                if (con_driver_map[i] == csw)
2620                        con_driver_map[i] = NULL;
2621}
2622
2623#endif
2624
2625/*
2626 *      Screen blanking
2627 */
2628
2629static void set_vesa_blanking(unsigned long arg)
2630{
2631        char *argp = (char *)arg + 1;
2632        unsigned int mode;
2633        if (get_user(mode, argp) == 0)
2634                vesa_blank_mode = (mode < 4) ? mode : 0;
2635}
2636
2637/* We can't register the console with devfs during con_init(), because it
2638 * is called before kmalloc() works.  This function is called later to
2639 * do the registration.
2640 */
2641void __init con_init_devfs (void)
2642{
2643        int i;
2644
2645        for (i = 0; i < console_driver.num; i++)
2646                tty_register_devfs (&console_driver, DEVFS_FL_AOPEN_NOTIFY,
2647                                    console_driver.minor_start + i);
2648}
2649
2650/*
2651 * This is called by a timer handler
2652 */
2653static void vesa_powerdown(void)
2654{
2655    struct vc_data *c = vc_cons[fg_console].d;
2656    /*
2657     *  Power down if currently suspended (1 or 2),
2658     *  suspend if currently blanked (0),
2659     *  else do nothing (i.e. already powered down (3)).
2660     *  Called only if powerdown features are allowed.
2661     */
2662    switch (vesa_blank_mode) {
2663        case VESA_NO_BLANKING:
2664            c->vc_sw->con_blank(c, VESA_VSYNC_SUSPEND+1);
2665            break;
2666        case VESA_VSYNC_SUSPEND:
2667        case VESA_HSYNC_SUSPEND:
2668            c->vc_sw->con_blank(c, VESA_POWERDOWN+1);
2669            break;
2670    }
2671}
2672
2673/*
2674 * This is a timer handler
2675 */
2676static void vesa_powerdown_screen(unsigned long dummy)
2677{
2678        console_timer.function = unblank_screen_t;
2679
2680        vesa_powerdown();
2681}
2682
2683static void timer_do_blank_screen(int entering_gfx, int from_timer_handler)
2684{
2685        int currcons = fg_console;
2686        int i;
2687
2688        if (console_blanked)
2689                return;
2690
2691        /* entering graphics mode? */
2692        if (entering_gfx) {
2693                hide_cursor(currcons);
2694                save_screen(currcons);
2695                sw->con_blank(vc_cons[currcons].d, -1);
2696                console_blanked = fg_console + 1;
2697                set_origin(currcons);
2698                return;
2699        }
2700
2701        /* don't blank graphics */
2702        if (vcmode != KD_TEXT) {
2703                console_blanked = fg_console + 1;
2704                return;
2705        }
2706
2707        hide_cursor(currcons);
2708        if (!from_timer_handler)
2709                del_timer_sync(&console_timer);
2710        if (vesa_off_interval) {
2711                console_timer.function = vesa_powerdown_screen;
2712                mod_timer(&console_timer, jiffies + vesa_off_interval);
2713        } else {
2714                if (!from_timer_handler)
2715                        del_timer_sync(&console_timer);
2716                console_timer.function = unblank_screen_t;
2717        }
2718
2719        save_screen(currcons);
2720        /* In case we need to reset origin, blanking hook returns 1 */
2721        i = sw->con_blank(vc_cons[currcons].d, 1);
2722        console_blanked = fg_console + 1;
2723        if (i)
2724                set_origin(currcons);
2725
2726        if (console_blank_hook && console_blank_hook(1))
2727                return;
2728        if (vesa_blank_mode)
2729                sw->con_blank(vc_cons[currcons].d, vesa_blank_mode + 1);
2730}
2731
2732void do_blank_screen(int entering_gfx)
2733{
2734        timer_do_blank_screen(entering_gfx, 0);
2735}
2736
2737/*
2738 * This is a timer handler
2739 */
2740static void unblank_screen_t(unsigned long dummy)
2741{
2742        unblank_screen();
2743}
2744
2745/*
2746 * Called by timer as well as from vt_console_driver
2747 */
2748void unblank_screen(void)
2749{
2750        int currcons;
2751
2752        if (!console_blanked)
2753                return;
2754        if (!vc_cons_allocated(fg_console)) {
2755                /* impossible */
2756                printk("unblank_screen: tty %d not allocated ??\n", fg_console+1);
2757                return;
2758        }
2759        currcons = fg_console;
2760        if (vcmode != KD_TEXT)
2761                return; /* but leave console_blanked != 0 */
2762
2763        console_timer.function = blank_screen;
2764        if (blankinterval) {
2765                mod_timer(&console_timer, jiffies + blankinterval);
2766        }
2767
2768        console_blanked = 0;
2769        if (console_blank_hook)
2770                console_blank_hook(0);
2771        set_palette(currcons);
2772        if (sw->con_blank(vc_cons[currcons].d, 0))
2773                /* Low-level driver cannot restore -> do it ourselves */
2774                update_screen(fg_console);
2775        set_cursor(fg_console);
2776}
2777
2778/*
2779 * This is both a user-level callable and a timer handler
2780 */
2781static void blank_screen(unsigned long dummy)
2782{
2783        timer_do_blank_screen(0, 1);
2784}
2785
2786void disable_console_blank(void)
2787{
2788        del_timer_sync(&console_timer);
2789        blankinterval = 0;
2790}
2791
2792void poke_blanked_console(void)
2793{
2794        del_timer(&console_timer);
2795        if (!vt_cons[fg_console] || vt_cons[fg_console]->vc_mode == KD_GRAPHICS)
2796                return;
2797        if (console_blanked) {
2798                console_timer.function = unblank_screen_t;
2799                mod_timer(&console_timer, jiffies);     /* Now */
2800        } else if (blankinterval) {
2801                mod_timer(&console_timer, jiffies + blankinterval);
2802        }
2803}
2804
2805/*
2806 *      Palettes
2807 */
2808
2809void set_palette(int currcons)
2810{
2811        if (vcmode != KD_GRAPHICS)
2812                sw->con_set_palette(vc_cons[currcons].d, color_table);
2813}
2814
2815static int set_get_cmap(unsigned char *arg, int set)
2816{
2817    int i, j, k;
2818
2819    for (i = 0; i < 16; i++)
2820        if (set) {
2821            get_user(default_red[i], arg++);
2822            get_user(default_grn[i], arg++);
2823            get_user(default_blu[i], arg++);
2824        } else {
2825            put_user(default_red[i], arg++);
2826            put_user(default_grn[i], arg++);
2827            put_user(default_blu[i], arg++);
2828        }
2829    if (set) {
2830        for (i = 0; i < MAX_NR_CONSOLES; i++)
2831            if (vc_cons_allocated(i)) {
2832                for (j = k = 0; j < 16; j++) {
2833                    vc_cons[i].d->vc_palette[k++] = default_red[j];
2834                    vc_cons[i].d->vc_palette[k++] = default_grn[j];
2835                    vc_cons[i].d->vc_palette[k++] = default_blu[j];
2836                }
2837                set_palette(i);
2838            }
2839    }
2840    return 0;
2841}
2842
2843/*
2844 * Load palette into the DAC registers. arg points to a colour
2845 * map, 3 bytes per colour, 16 colours, range from 0 to 255.
2846 */
2847
2848int con_set_cmap(unsigned char *arg)
2849{
2850        return set_get_cmap (arg,1);
2851}
2852
2853int con_get_cmap(unsigned char *arg)
2854{
2855        return set_get_cmap (arg,0);
2856}
2857
2858void reset_palette(int currcons)
2859{
2860        int j, k;
2861        for (j=k=0; j<16; j++) {
2862                palette[k++] = default_red[j];
2863                palette[k++] = default_grn[j];
2864                palette[k++] = default_blu[j];
2865        }
2866        set_palette(currcons);
2867}
2868
2869/*
2870 *  Font switching
2871 *
2872 *  Currently we only support fonts up to 32 pixels wide, at a maximum height
2873 *  of 32 pixels. Userspace fontdata is stored with 32 bytes (shorts/ints, 
2874 *  depending on width) reserved for each character which is kinda wasty, but 
2875 *  this is done in order to maintain compatibility with the EGA/VGA fonts. It 
2876 *  is upto the actual low-level console-driver convert data into its favorite
2877 *  format (maybe we should add a `fontoffset' field to the `display'
2878 *  structure so we wont have to convert the fontdata all the time.
2879 *  /Jes
2880 */
2881
2882#define max_font_size 65536
2883
2884int con_font_op(int currcons, struct console_font_op *op)
2885{
2886        int rc = -EINVAL;
2887        int size = max_font_size, set;
2888        u8 *temp = NULL;
2889        struct console_font_op old_op;
2890
2891        if (vt_cons[currcons]->vc_mode != KD_TEXT)
2892                goto quit;
2893        memcpy(&old_op, op, sizeof(old_op));
2894        if (op->op == KD_FONT_OP_SET) {
2895                if (!op->data)
2896                        return -EINVAL;
2897                if (op->charcount > 512)
2898                        goto quit;
2899                if (!op->height) {              /* Need to guess font height [compat] */
2900                        int h, i;
2901                        u8 *charmap = op->data, tmp;
2902                        
2903                        /* If from KDFONTOP ioctl, don't allow things which can be done in userland,
2904                           so that we can get rid of this soon */
2905                        if (!(op->flags & KD_FONT_FLAG_OLD))
2906                                goto quit;
2907                        rc = -EFAULT;
2908                        for (h = 32; h > 0; h--)
2909                                for (i = 0; i < op->charcount; i++) {
2910                                        if (get_user(tmp, &charmap[32*i+h-1]))
2911                                                goto quit;
2912                                        if (tmp)
2913                                                goto nonzero;
2914                                }
2915                        rc = -EINVAL;
2916                        goto quit;
2917                nonzero:
2918                        rc = -EINVAL;
2919                        op->height = h;
2920                }
2921                if (op->width > 32 || op->height > 32)
2922                        goto quit;
2923                size = (op->width+7)/8 * 32 * op->charcount;
2924                if (size > max_font_size)
2925                        return -ENOSPC;
2926                set = 1;
2927        } else if (op->op == KD_FONT_OP_GET)
2928                set = 0;
2929        else
2930                return sw->con_font_op(vc_cons[currcons].d, op);
2931        if (op->data) {
2932                temp = kmalloc(size, GFP_KERNEL);
2933                if (!temp)
2934                        return -ENOMEM;
2935                if (set && copy_from_user(temp, op->data, size)) {
2936                        rc = -EFAULT;
2937                        goto quit;
2938                }
2939                op->data = temp;
2940        }
2941
2942        acquire_console_sem();
2943        rc = sw->con_font_op(vc_cons[currcons].d, op);
2944        release_console_sem();
2945
2946        op->data = old_op.data;
2947        if (!rc && !set) {
2948                int c = (op->width+7)/8 * 32 * op->charcount;
2949                
2950                if (op->data && op->charcount > old_op.charcount)
2951                        rc = -ENOSPC;
2952                if (!(op->flags & KD_FONT_FLAG_OLD)) {
2953                        if (op->width > old_op.width || 
2954                            op->height > old_op.height)
2955                                rc = -ENOSPC;
2956                } else {
2957                        if (op->width != 8)
2958                                rc = -EIO;
2959                        else if ((old_op.height && op->height > old_op.height) ||
2960                                 op->height > 32)
2961                                rc = -ENOSPC;
2962                }
2963                if (!rc && op->data && copy_to_user(op->data, temp, c))
2964                        rc = -EFAULT;
2965        }
2966quit:   if (temp)
2967                kfree(temp);
2968        return rc;
2969}
2970
2971/*
2972 *      Interface exported to selection and vcs.
2973 */
2974
2975/* used by selection */
2976u16 screen_glyph(int currcons, int offset)
2977{
2978        u16 w = scr_readw(screenpos(currcons, offset, 1));
2979        u16 c = w & 0xff;
2980
2981        if (w & hi_font_mask)
2982                c |= 0x100;
2983        return c;
2984}
2985
2986/* used by vcs - note the word offset */
2987unsigned short *screen_pos(int currcons, int w_offset, int viewed)
2988{
2989        return screenpos(currcons, 2 * w_offset, viewed);
2990}
2991
2992void getconsxy(int currcons, char *p)
2993{
2994        p[0] = x;
2995        p[1] = y;
2996}
2997
2998void putconsxy(int currcons, char *p)
2999{
3000        gotoxy(currcons, p[0], p[1]);
3001        set_cursor(currcons);
3002}
3003
3004u16 vcs_scr_readw(int currcons, const u16 *org)
3005{
3006        if ((unsigned long)org == pos && softcursor_original != -1)
3007                return softcursor_original;
3008        return scr_readw(org);
3009}
3010
3011void vcs_scr_writew(int currcons, u16 val, u16 *org)
3012{
3013        scr_writew(val, org);
3014        if ((unsigned long)org == pos) {
3015                softcursor_original = -1;
3016                add_softcursor(currcons);
3017        }
3018}
3019
3020static int pm_con_request(struct pm_dev *dev, pm_request_t rqst, void *data)
3021{
3022        switch (rqst)
3023        {
3024        case PM_RESUME:
3025                unblank_screen();
3026                break;
3027        case PM_SUSPEND:
3028                do_blank_screen(0);
3029                break;
3030        }
3031        return 0;
3032}
3033
3034/*
3035 *      Visible symbols for modules
3036 */
3037
3038EXPORT_SYMBOL(color_table);
3039EXPORT_SYMBOL(default_red);
3040EXPORT_SYMBOL(default_grn);
3041EXPORT_SYMBOL(default_blu);
3042EXPORT_SYMBOL(video_font_height);
3043EXPORT_SYMBOL(video_scan_lines);
3044EXPORT_SYMBOL(vc_resize);
3045EXPORT_SYMBOL(fg_console);
3046EXPORT_SYMBOL(console_blank_hook);
3047#ifdef CONFIG_VT
3048EXPORT_SYMBOL(vt_cons);
3049#endif
3050#ifndef VT_SINGLE_DRIVER
3051EXPORT_SYMBOL(take_over_console);
3052EXPORT_SYMBOL(give_up_console);
3053#endif
3054
lxr.linux.no kindly hosted by Redpill Linpro AS, provider of Linux consulting and operations services since 1995.