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