Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux
1
fork

Configure Feed

Select the types of activity you want to include in your feed.

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