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

Configure Feed

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

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