/* * linux/drivers/char/vt.c * * Copyright (C) 1991, 1992 Linus Torvalds */ /* * Hopefully this will be a rather complete VT102 implementation. * * Beeping thanks to John T Kohl. * * Virtual Consoles, Screen Blanking, Screen Dumping, Color, Graphics * Chars, and VT100 enhancements by Peter MacDonald. * * Copy and paste function by Andrew Haylett, * some enhancements by Alessandro Rubini. * * Code to check for different video-cards mostly by Galen Hunt, * <g-hunt@ee.utah.edu> * * Rudimentary ISO 10646/Unicode/UTF-8 character set support by * Markus Kuhn, <mskuhn@immd4.informatik.uni-erlangen.de>. * * Dynamic allocation of consoles, aeb@cwi.nl, May 1994 * Resizing of consoles, aeb, 940926 * * Code for xterm like mouse click reporting by Peter Orbaek 20-Jul-94 * <poe@daimi.aau.dk> * * User-defined bell sound, new setterm control sequences and printk * redirection by Martin Mares <mj@k332.feld.cvut.cz> 19-Nov-95 * * APM screenblank bug fixed Takashi Manabe <manabe@roy.dsl.tutics.tut.jp> * * Merge with the abstract console driver by Geert Uytterhoeven * <geert@linux-m68k.org>, Jan 1997. * * Original m68k console driver modifications by * * - Arno Griffioen <arno@usn.nl> * - David Carter <carter@cs.bris.ac.uk> * * The abstract console driver provides a generic interface for a text * console. It supports VGA text mode, frame buffer based graphical consoles * and special graphics processors that are only accessible through some * registers (e.g. a TMS340x0 GSP). * * The interface to the hardware is specified using a special structure * (struct consw) which contains function pointers to console operations * (see <linux/console.h> for more information). * * Support for changeable cursor shape * by Pavel Machek <pavel@atrey.karlin.mff.cuni.cz>, August 1997 * * Ported to i386 and con_scrolldelta fixed * by Emmanuel Marty <core@ggi-project.org>, April 1998 * * Resurrected character buffers in videoram plus lots of other trickery * by Martin Mares <mj@atrey.karlin.mff.cuni.cz>, July 1998 * * Removed old-style timers, introduced console_timer, made timer * deletion SMP-safe. 17Jun00, Andrew Morton <andrewm@uow.edu.au> * * Removed console_lock, enabled interrupts across all console operations * 13 March 2001, Andrew Morton * * Fixed UTF-8 mode so alternate charset modes always work according * to control sequences interpreted in do_con_trol function * preserving backward VT100 semigraphics compatibility, * malformed UTF sequences represented as sequences of replacement glyphs, * original codes or '?' as a last resort if replacement glyph is undefined * by Adam Tla/lka <atlka@pg.gda.pl>, Aug 2006 */ #include <linux/module.h>#include <linux/types.h>#include <linux/sched.h>#include <linux/tty.h>#include <linux/tty_flip.h>#include <linux/kernel.h>#include <linux/string.h>#include <linux/errno.h>#include <linux/kd.h>#include <linux/slab.h>#include <linux/major.h>#include <linux/mm.h>#include <linux/console.h>#include <linux/init.h>#include <linux/vt_kern.h>#include <linux/selection.h>#include <linux/tiocl.h>#include <linux/kbd_kern.h>#include <linux/consolemap.h>#include <linux/timer.h>#include <linux/interrupt.h>#include <linux/workqueue.h>#include <linux/bootmem.h>#include <linux/pm.h>#include <linux/font.h>#include <linux/bitops.h> #include <asm/io.h>#include <asm/system.h>#include <asm/uaccess.h> #define MAX_NR_CON_DRIVER 16 #define CON_DRIVER_FLAG_MODULE 1#define CON_DRIVER_FLAG_INIT 2#define CON_DRIVER_FLAG_ATTR 4 struct con_driver { const struct consw *con; const char *desc; struct device *dev; int node; int first; int last; int flag;}; static struct con_driver registered_con_driver[MAX_NR_CON_DRIVER];const struct consw *conswitchp; /* A bitmap for codes <32. A bit of 1 indicates that the code * corresponding to that bit number invokes some special action * (such as cursor movement) and should not be displayed as a * glyph unless the disp_ctrl mode is explicitly enabled. */#define CTRL_ACTION 0x0d00ff81#define CTRL_ALWAYS 0x0800f501 /* Cannot be overridden by disp_ctrl */ /* * Here is the default bell parameters: 750HZ, 1/8th of a second */#define DEFAULT_BELL_PITCH 750#define DEFAULT_BELL_DURATION (HZ/8) struct vc vc_cons [MAX_NR_CONSOLES]; #ifndef VT_SINGLE_DRIVERstatic const struct consw *con_driver_map[MAX_NR_CONSOLES];#endif static int con_open(struct tty_struct *, struct file *);static void vc_init(struct vc_data *vc, unsigned int rows, unsigned int cols, int do_clear);static void gotoxy(struct vc_data *vc, int new_x, int new_y);static void save_cur(struct vc_data *vc);static void reset_terminal(struct vc_data *vc, int do_clear);static void con_flush_chars(struct tty_struct *tty);static int set_vesa_blanking(char __user *p);static void set_cursor(struct vc_data *vc);static void hide_cursor(struct vc_data *vc);static void console_callback(struct work_struct *ignored);static void blank_screen_t(unsigned long dummy);static void set_palette(struct vc_data *vc); static int printable; /* Is console ready for printing? */ /* * ignore_poke: don't unblank the screen when things are typed. This is * mainly for the privacy of braille terminal users. */static int ignore_poke; int do_poke_blanked_console;int console_blanked; static int vesa_blank_mode; /* 0:none 1:suspendV 2:suspendH 3:powerdown */static int blankinterval = 10*60*HZ;static int vesa_off_interval; static DECLARE_WORK(console_work, console_callback); /* * fg_console is the current virtual console, * last_console is the last used one, * want_console is the console we want to switch to, * kmsg_redirect is the console for kernel messages, */int fg_console;int last_console;int want_console = -1;int kmsg_redirect; /* * For each existing display, we have a pointer to console currently visible * on that display, allowing consoles other than fg_console to be refreshed * appropriately. Unless the low-level driver supplies its own display_fg * variable, we use this one for the "master display". */static struct vc_data *master_display_fg; /* * Unfortunately, we need to delay tty echo when we're currently writing to the * console since the code is (and always was) not re-entrant, so we schedule * all flip requests to process context with schedule-task() and run it from * console_callback(). */ /* * For the same reason, we defer scrollback to the console callback. */static int scrollback_delta; /* * Hook so that the power management routines can (un)blank * the console on our behalf. */int (*console_blank_hook)(int); static DEFINE_TIMER(console_timer, blank_screen_t, 0, 0);static int blank_state;static int blank_timer_expired;enum { blank_off = 0, blank_normal_wait, blank_vesa_wait,}; /* * Low-Level Functions */ #define IS_FG(vc) ((vc)->vc_num == fg_console) #ifdef VT_BUF_VRAM_ONLY#define DO_UPDATE(vc) 0#else#define DO_UPDATE(vc) CON_IS_VISIBLE(vc)#endif static inline unsigned short *screenpos(struct vc_data *vc, int offset, int viewed){ unsigned short *p; if (!viewed) p = (unsigned short *)(vc->vc_origin + offset); else if (!vc->vc_sw->con_screen_pos) p = (unsigned short *)(vc->vc_visible_origin + offset); else p = vc->vc_sw->con_screen_pos(vc, offset); return p;} static inline void scrolldelta(int lines){ scrollback_delta += lines; schedule_console_callback();} void schedule_console_callback(void){ schedule_work(&console_work);} static void scrup(struct vc_data *vc, unsigned int t, unsigned int b, int nr){ unsigned short *d, *s; if (t+nr >= b) nr = b - t - 1; if (b > vc->vc_rows || t >= b || nr < 1) return; if (CON_IS_VISIBLE(vc) && vc->vc_sw->con_scroll(vc, t, b, SM_UP, nr)) return; d = (unsigned short *)(vc->vc_origin + vc->vc_size_row * t); s = (unsigned short *)(vc->vc_origin + vc->vc_size_row * (t + nr)); scr_memmovew(d, s, (b - t - nr) * vc->vc_size_row); scr_memsetw(d + (b - t - nr) * vc->vc_cols, vc->vc_video_erase_char, vc->vc_size_row * nr);} static void scrdown(struct vc_data *vc, unsigned int t, unsigned int b, int nr){ unsigned short *s; unsigned int step; if (t+nr >= b) nr = b - t - 1; if (b > vc->vc_rows || t >= b || nr < 1) return; if (CON_IS_VISIBLE(vc) && vc->vc_sw->con_scroll(vc, t, b, SM_DOWN, nr)) return; s = (unsigned short *)(vc->vc_origin + vc->vc_size_row * t); step = vc->vc_cols * nr; scr_memmovew(s + step, s, (b - t - nr) * vc->vc_size_row); scr_memsetw(s, vc->vc_video_erase_char, 2 * step);} static void do_update_region(struct vc_data *vc, unsigned long start, int count){#ifndef VT_BUF_VRAM_ONLY unsigned int xx, yy, offset; u16 *p; p = (u16 *) start; if (!vc->vc_sw->con_getxy) { offset = (start - vc->vc_origin) / 2; xx = offset % vc->vc_cols; yy = offset / vc->vc_cols; } else { int nxx, nyy; start = vc->vc_sw->con_getxy(vc, start, &nxx, &nyy); xx = nxx; yy = nyy; } for(;;) { u16 attrib = scr_readw(p) & 0xff00; int startx = xx; u16 *q = p; while (xx < vc->vc_cols && count) { if (attrib != (scr_readw(p) & 0xff00)) { if (p > q) vc->vc_sw->con_putcs(vc, q, p-q, yy, startx); startx = xx; q = p; attrib = scr_readw(p) & 0xff00; } p++; xx++; count--; } if (p > q) vc->vc_sw->con_putcs(vc, q, p-q, yy, startx); if (!count) break; xx = 0; yy++; if (vc->vc_sw->con_getxy) { p = (u16 *)start; start = vc->vc_sw->con_getxy(vc, start, NULL, NULL); } }#endif} void update_region(struct vc_data *vc, unsigned long start, int count){ WARN_CONSOLE_UNLOCKED(); if (DO_UPDATE(vc)) { hide_cursor(vc); do_update_region(vc, start, count); set_cursor(vc); }} /* Structure of attributes is hardware-dependent */ static u8 build_attr(struct vc_data *vc, u8 _color, u8 _intensity, u8 _blink, u8 _underline, u8 _reverse){ if (vc->vc_sw->con_build_attr) return vc->vc_sw->con_build_attr(vc, _color, _intensity, _blink, _underline, _reverse); #ifndef VT_BUF_VRAM_ONLY/* * ++roman: I completely changed the attribute format for monochrome * mode (!can_do_color). The formerly used MDA (monochrome display * adapter) format didn't allow the combination of certain effects. * Now the attribute is just a bit vector: * Bit 0..1: intensity (0..2) * Bit 2 : underline * Bit 3 : reverse * Bit 7 : blink */ { u8 a = vc->vc_color; if (!vc->vc_can_do_color) return _intensity | (_underline ? 4 : 0) | (_reverse ? 8 : 0) | (_blink ? 0x80 : 0); if (_underline) a = (a & 0xf0) | vc->vc_ulcolor; else if (_intensity == 0) a = (a & 0xf0) | vc->vc_ulcolor; if (_reverse) a = ((a) & 0x88) | ((((a) >> 4) | ((a) << 4)) & 0x77); if (_blink) a ^= 0x80; if (_intensity == 2) a ^= 0x08; if (vc->vc_hi_font_mask == 0x100) a <<= 1; return a; }#else return 0;#endif} static void update_attr(struct vc_data *vc){ vc->vc_attr = build_attr(vc, vc->vc_color, vc->vc_intensity, vc->vc_blink, vc->vc_underline, vc->vc_reverse ^ vc->vc_decscnm); vc->vc_video_erase_char = (build_attr(vc, vc->vc_color, 1, vc->vc_blink, 0, vc->vc_decscnm) << 8) | ' ';} /* Note: inverting the screen twice should revert to the original state */void invert_screen(struct vc_data *vc, int offset, int count, int viewed){ unsigned short *p; WARN_CONSOLE_UNLOCKED(); count /= 2; p = screenpos(vc, offset, viewed); if (vc->vc_sw->con_invert_region) vc->vc_sw->con_invert_region(vc, p, count);#ifndef VT_BUF_VRAM_ONLY else { u16 *q = p; int cnt = count; u16 a; if (!vc->vc_can_do_color) { while (cnt--) { a = scr_readw(q); a ^= 0x0800; scr_writew(a, q); q++; } } else if (vc->vc_hi_font_mask == 0x100) { while (cnt--) { a = scr_readw(q); a = ((a) & 0x11ff) | (((a) & 0xe000) >> 4) | (((a) & 0x0e00) << 4); scr_writew(a, q); q++; } } else { while (cnt--) { a = scr_readw(q); a = ((a) & 0x88ff) | (((a) & 0x7000) >> 4) | (((a) & 0x0700) << 4); scr_writew(a, q); q++; } } }#endif if (DO_UPDATE(vc)) do_update_region(vc, (unsigned long) p, count);} /* used by selection: complement pointer position */void complement_pos(struct vc_data *vc, int offset){ static int old_offset = -1; static unsigned short old; static unsigned short oldx, oldy; WARN_CONSOLE_UNLOCKED(); if (old_offset != -1 && old_offset >= 0 && old_offset < vc->vc_screenbuf_size) { scr_writew(old, screenpos(vc, old_offset, 1)); if (DO_UPDATE(vc)) vc->vc_sw->con_putc(vc, old, oldy, oldx); } old_offset = offset; if (offset != -1 && offset >= 0 && offset < vc->vc_screenbuf_size) { unsigned short new; unsigned short *p; p = screenpos(vc, offset, 1); old = scr_readw(p); new = old ^ vc->vc_complement_mask; scr_writew(new, p); if (DO_UPDATE(vc)) { oldx = (offset >> 1) % vc->vc_cols; oldy = (offset >> 1) / vc->vc_cols; vc->vc_sw->con_putc(vc, new, oldy, oldx); } } } static void insert_char(struct vc_data *vc, unsigned int nr){ unsigned short *p, *q = (unsigned short *)vc->vc_pos; p = q + vc->vc_cols - nr - vc->vc_x; while (--p >= q) scr_writew(scr_readw(p), p + nr); scr_memsetw(q, vc->vc_video_erase_char, nr * 2); vc->vc_need_wrap = 0; if (DO_UPDATE(vc)) { unsigned short oldattr = vc->vc_attr; vc->vc_sw->con_bmove(vc, vc->vc_y, vc->vc_x, vc->vc_y, vc->vc_x + nr, 1, vc->vc_cols - vc->vc_x - nr); vc->vc_attr = vc->vc_video_erase_char >> 8; while (nr--) vc->vc_sw->con_putc(vc, vc->vc_video_erase_char, vc->vc_y, vc->vc_x + nr); vc->vc_attr = oldattr; }} static void delete_char(struct vc_data *vc, unsigned int nr){Lines 1–500 of 3837. Load more
/* * linux/drivers/char/vt.c * * Copyright (C) 1991, 1992 Linus Torvalds */ /* * Hopefully this will be a rather complete VT102 implementation. * * Beeping thanks to John T Kohl. * * Virtual Consoles, Screen Blanking, Screen Dumping, Color, Graphics * Chars, and VT100 enhancements by Peter MacDonald. * * Copy and paste function by Andrew Haylett, * some enhancements by Alessandro Rubini. * * Code to check for different video-cards mostly by Galen Hunt, * <g-hunt@ee.utah.edu> * * Rudimentary ISO 10646/Unicode/UTF-8 character set support by * Markus Kuhn, <mskuhn@immd4.informatik.uni-erlangen.de>. * * Dynamic allocation of consoles, aeb@cwi.nl, May 1994 * Resizing of consoles, aeb, 940926 * * Code for xterm like mouse click reporting by Peter Orbaek 20-Jul-94 * <poe@daimi.aau.dk> * * User-defined bell sound, new setterm control sequences and printk * redirection by Martin Mares <mj@k332.feld.cvut.cz> 19-Nov-95 * * APM screenblank bug fixed Takashi Manabe <manabe@roy.dsl.tutics.tut.jp> * * Merge with the abstract console driver by Geert Uytterhoeven * <geert@linux-m68k.org>, Jan 1997. * * Original m68k console driver modifications by * * - Arno Griffioen <arno@usn.nl> * - David Carter <carter@cs.bris.ac.uk> * * The abstract console driver provides a generic interface for a text * console. It supports VGA text mode, frame buffer based graphical consoles * and special graphics processors that are only accessible through some * registers (e.g. a TMS340x0 GSP). * * The interface to the hardware is specified using a special structure * (struct consw) which contains function pointers to console operations * (see <linux/console.h> for more information). * * Support for changeable cursor shape * by Pavel Machek <pavel@atrey.karlin.mff.cuni.cz>, August 1997 * * Ported to i386 and con_scrolldelta fixed * by Emmanuel Marty <core@ggi-project.org>, April 1998 * * Resurrected character buffers in videoram plus lots of other trickery * by Martin Mares <mj@atrey.karlin.mff.cuni.cz>, July 1998 * * Removed old-style timers, introduced console_timer, made timer * deletion SMP-safe. 17Jun00, Andrew Morton <andrewm@uow.edu.au> * * Removed console_lock, enabled interrupts across all console operations * 13 March 2001, Andrew Morton * * Fixed UTF-8 mode so alternate charset modes always work according * to control sequences interpreted in do_con_trol function * preserving backward VT100 semigraphics compatibility, * malformed UTF sequences represented as sequences of replacement glyphs, * original codes or '?' as a last resort if replacement glyph is undefined * by Adam Tla/lka <atlka@pg.gda.pl>, Aug 2006 */ #include <linux/module.h> #include <linux/types.h> #include <linux/sched.h> #include <linux/tty.h> #include <linux/tty_flip.h> #include <linux/kernel.h> #include <linux/string.h> #include <linux/errno.h> #include <linux/kd.h> #include <linux/slab.h> #include <linux/major.h> #include <linux/mm.h> #include <linux/console.h> #include <linux/init.h> #include <linux/vt_kern.h> #include <linux/selection.h> #include <linux/tiocl.h> #include <linux/kbd_kern.h> #include <linux/consolemap.h> #include <linux/timer.h> #include <linux/interrupt.h> #include <linux/workqueue.h> #include <linux/bootmem.h> #include <linux/pm.h> #include <linux/font.h> #include <linux/bitops.h> #include <asm/io.h> #include <asm/system.h> #include <asm/uaccess.h> #define MAX_NR_CON_DRIVER 16 #define CON_DRIVER_FLAG_MODULE 1 #define CON_DRIVER_FLAG_INIT 2 #define CON_DRIVER_FLAG_ATTR 4 struct con_driver { const struct consw *con; const char *desc; struct device *dev; int node; int first; int last; int flag; }; static struct con_driver registered_con_driver[MAX_NR_CON_DRIVER]; const struct consw *conswitchp; /* A bitmap for codes <32. A bit of 1 indicates that the code * corresponding to that bit number invokes some special action * (such as cursor movement) and should not be displayed as a * glyph unless the disp_ctrl mode is explicitly enabled. */ #define CTRL_ACTION 0x0d00ff81 #define CTRL_ALWAYS 0x0800f501 /* Cannot be overridden by disp_ctrl */ /* * Here is the default bell parameters: 750HZ, 1/8th of a second */ #define DEFAULT_BELL_PITCH 750 #define DEFAULT_BELL_DURATION (HZ/8) struct vc vc_cons [MAX_NR_CONSOLES]; #ifndef VT_SINGLE_DRIVER static const struct consw *con_driver_map[MAX_NR_CONSOLES]; #endif static int con_open(struct tty_struct *, struct file *); static void vc_init(struct vc_data *vc, unsigned int rows, unsigned int cols, int do_clear); static void gotoxy(struct vc_data *vc, int new_x, int new_y); static void save_cur(struct vc_data *vc); static void reset_terminal(struct vc_data *vc, int do_clear); static void con_flush_chars(struct tty_struct *tty); static int set_vesa_blanking(char __user *p); static void set_cursor(struct vc_data *vc); static void hide_cursor(struct vc_data *vc); static void console_callback(struct work_struct *ignored); static void blank_screen_t(unsigned long dummy); static void set_palette(struct vc_data *vc); static int printable; /* Is console ready for printing? */ /* * ignore_poke: don't unblank the screen when things are typed. This is * mainly for the privacy of braille terminal users. */ static int ignore_poke; int do_poke_blanked_console; int console_blanked; static int vesa_blank_mode; /* 0:none 1:suspendV 2:suspendH 3:powerdown */ static int blankinterval = 10*60*HZ; static int vesa_off_interval; static DECLARE_WORK(console_work, console_callback); /* * fg_console is the current virtual console, * last_console is the last used one, * want_console is the console we want to switch to, * kmsg_redirect is the console for kernel messages, */ int fg_console; int last_console; int want_console = -1; int kmsg_redirect; /* * For each existing display, we have a pointer to console currently visible * on that display, allowing consoles other than fg_console to be refreshed * appropriately. Unless the low-level driver supplies its own display_fg * variable, we use this one for the "master display". */ static struct vc_data *master_display_fg; /* * Unfortunately, we need to delay tty echo when we're currently writing to the * console since the code is (and always was) not re-entrant, so we schedule * all flip requests to process context with schedule-task() and run it from * console_callback(). */ /* * For the same reason, we defer scrollback to the console callback. */ static int scrollback_delta; /* * Hook so that the power management routines can (un)blank * the console on our behalf. */ int (*console_blank_hook)(int); static DEFINE_TIMER(console_timer, blank_screen_t, 0, 0); static int blank_state; static int blank_timer_expired; enum { blank_off = 0, blank_normal_wait, blank_vesa_wait, }; /* * Low-Level Functions */ #define IS_FG(vc) ((vc)->vc_num == fg_console) #ifdef VT_BUF_VRAM_ONLY #define DO_UPDATE(vc) 0 #else #define DO_UPDATE(vc) CON_IS_VISIBLE(vc) #endif static inline unsigned short *screenpos(struct vc_data *vc, int offset, int viewed) { unsigned short *p; if (!viewed) p = (unsigned short *)(vc->vc_origin + offset); else if (!vc->vc_sw->con_screen_pos) p = (unsigned short *)(vc->vc_visible_origin + offset); else p = vc->vc_sw->con_screen_pos(vc, offset); return p; } static inline void scrolldelta(int lines) { scrollback_delta += lines; schedule_console_callback(); } void schedule_console_callback(void) { schedule_work(&console_work); } static void scrup(struct vc_data *vc, unsigned int t, unsigned int b, int nr) { unsigned short *d, *s; if (t+nr >= b) nr = b - t - 1; if (b > vc->vc_rows || t >= b || nr < 1) return; if (CON_IS_VISIBLE(vc) && vc->vc_sw->con_scroll(vc, t, b, SM_UP, nr)) return; d = (unsigned short *)(vc->vc_origin + vc->vc_size_row * t); s = (unsigned short *)(vc->vc_origin + vc->vc_size_row * (t + nr)); scr_memmovew(d, s, (b - t - nr) * vc->vc_size_row); scr_memsetw(d + (b - t - nr) * vc->vc_cols, vc->vc_video_erase_char, vc->vc_size_row * nr); } static void scrdown(struct vc_data *vc, unsigned int t, unsigned int b, int nr) { unsigned short *s; unsigned int step; if (t+nr >= b) nr = b - t - 1; if (b > vc->vc_rows || t >= b || nr < 1) return; if (CON_IS_VISIBLE(vc) && vc->vc_sw->con_scroll(vc, t, b, SM_DOWN, nr)) return; s = (unsigned short *)(vc->vc_origin + vc->vc_size_row * t); step = vc->vc_cols * nr; scr_memmovew(s + step, s, (b - t - nr) * vc->vc_size_row); scr_memsetw(s, vc->vc_video_erase_char, 2 * step); } static void do_update_region(struct vc_data *vc, unsigned long start, int count) { #ifndef VT_BUF_VRAM_ONLY unsigned int xx, yy, offset; u16 *p; p = (u16 *) start; if (!vc->vc_sw->con_getxy) { offset = (start - vc->vc_origin) / 2; xx = offset % vc->vc_cols; yy = offset / vc->vc_cols; } else { int nxx, nyy; start = vc->vc_sw->con_getxy(vc, start, &nxx, &nyy); xx = nxx; yy = nyy; } for(;;) { u16 attrib = scr_readw(p) & 0xff00; int startx = xx; u16 *q = p; while (xx < vc->vc_cols && count) { if (attrib != (scr_readw(p) & 0xff00)) { if (p > q) vc->vc_sw->con_putcs(vc, q, p-q, yy, startx); startx = xx; q = p; attrib = scr_readw(p) & 0xff00; } p++; xx++; count--; } if (p > q) vc->vc_sw->con_putcs(vc, q, p-q, yy, startx); if (!count) break; xx = 0; yy++; if (vc->vc_sw->con_getxy) { p = (u16 *)start; start = vc->vc_sw->con_getxy(vc, start, NULL, NULL); } } #endif } void update_region(struct vc_data *vc, unsigned long start, int count) { WARN_CONSOLE_UNLOCKED(); if (DO_UPDATE(vc)) { hide_cursor(vc); do_update_region(vc, start, count); set_cursor(vc); } } /* Structure of attributes is hardware-dependent */ static u8 build_attr(struct vc_data *vc, u8 _color, u8 _intensity, u8 _blink, u8 _underline, u8 _reverse) { if (vc->vc_sw->con_build_attr) return vc->vc_sw->con_build_attr(vc, _color, _intensity, _blink, _underline, _reverse); #ifndef VT_BUF_VRAM_ONLY /* * ++roman: I completely changed the attribute format for monochrome * mode (!can_do_color). The formerly used MDA (monochrome display * adapter) format didn't allow the combination of certain effects. * Now the attribute is just a bit vector: * Bit 0..1: intensity (0..2) * Bit 2 : underline * Bit 3 : reverse * Bit 7 : blink */ { u8 a = vc->vc_color; if (!vc->vc_can_do_color) return _intensity | (_underline ? 4 : 0) | (_reverse ? 8 : 0) | (_blink ? 0x80 : 0); if (_underline) a = (a & 0xf0) | vc->vc_ulcolor; else if (_intensity == 0) a = (a & 0xf0) | vc->vc_ulcolor; if (_reverse) a = ((a) & 0x88) | ((((a) >> 4) | ((a) << 4)) & 0x77); if (_blink) a ^= 0x80; if (_intensity == 2) a ^= 0x08; if (vc->vc_hi_font_mask == 0x100) a <<= 1; return a; } #else return 0; #endif } static void update_attr(struct vc_data *vc) { vc->vc_attr = build_attr(vc, vc->vc_color, vc->vc_intensity, vc->vc_blink, vc->vc_underline, vc->vc_reverse ^ vc->vc_decscnm); vc->vc_video_erase_char = (build_attr(vc, vc->vc_color, 1, vc->vc_blink, 0, vc->vc_decscnm) << 8) | ' '; } /* Note: inverting the screen twice should revert to the original state */ void invert_screen(struct vc_data *vc, int offset, int count, int viewed) { unsigned short *p; WARN_CONSOLE_UNLOCKED(); count /= 2; p = screenpos(vc, offset, viewed); if (vc->vc_sw->con_invert_region) vc->vc_sw->con_invert_region(vc, p, count); #ifndef VT_BUF_VRAM_ONLY else { u16 *q = p; int cnt = count; u16 a; if (!vc->vc_can_do_color) { while (cnt--) { a = scr_readw(q); a ^= 0x0800; scr_writew(a, q); q++; } } else if (vc->vc_hi_font_mask == 0x100) { while (cnt--) { a = scr_readw(q); a = ((a) & 0x11ff) | (((a) & 0xe000) >> 4) | (((a) & 0x0e00) << 4); scr_writew(a, q); q++; } } else { while (cnt--) { a = scr_readw(q); a = ((a) & 0x88ff) | (((a) & 0x7000) >> 4) | (((a) & 0x0700) << 4); scr_writew(a, q); q++; } } } #endif if (DO_UPDATE(vc)) do_update_region(vc, (unsigned long) p, count); } /* used by selection: complement pointer position */ void complement_pos(struct vc_data *vc, int offset) { static int old_offset = -1; static unsigned short old; static unsigned short oldx, oldy; WARN_CONSOLE_UNLOCKED(); if (old_offset != -1 && old_offset >= 0 && old_offset < vc->vc_screenbuf_size) { scr_writew(old, screenpos(vc, old_offset, 1)); if (DO_UPDATE(vc)) vc->vc_sw->con_putc(vc, old, oldy, oldx); } old_offset = offset; if (offset != -1 && offset >= 0 && offset < vc->vc_screenbuf_size) { unsigned short new; unsigned short *p; p = screenpos(vc, offset, 1); old = scr_readw(p); new = old ^ vc->vc_complement_mask; scr_writew(new, p); if (DO_UPDATE(vc)) { oldx = (offset >> 1) % vc->vc_cols; oldy = (offset >> 1) / vc->vc_cols; vc->vc_sw->con_putc(vc, new, oldy, oldx); } } } static void insert_char(struct vc_data *vc, unsigned int nr) { unsigned short *p, *q = (unsigned short *)vc->vc_pos; p = q + vc->vc_cols - nr - vc->vc_x; while (--p >= q) scr_writew(scr_readw(p), p + nr); scr_memsetw(q, vc->vc_video_erase_char, nr * 2); vc->vc_need_wrap = 0; if (DO_UPDATE(vc)) { unsigned short oldattr = vc->vc_attr; vc->vc_sw->con_bmove(vc, vc->vc_y, vc->vc_x, vc->vc_y, vc->vc_x + nr, 1, vc->vc_cols - vc->vc_x - nr); vc->vc_attr = vc->vc_video_erase_char >> 8; while (nr--) vc->vc_sw->con_putc(vc, vc->vc_video_erase_char, vc->vc_y, vc->vc_x + nr); vc->vc_attr = oldattr; } } static void delete_char(struct vc_data *vc, unsigned int nr) {