summaryrefslogtreecommitdiffstats
path: root/drivers/char/console.c
diff options
context:
space:
mode:
Diffstat (limited to 'drivers/char/console.c')
-rw-r--r--drivers/char/console.c2986
1 files changed, 1572 insertions, 1414 deletions
diff --git a/drivers/char/console.c b/drivers/char/console.c
index 9c9e61e8c..d5b315328 100644
--- a/drivers/char/console.c
+++ b/drivers/char/console.c
@@ -3,38 +3,8 @@
*
* Copyright (C) 1991, 1992 Linus Torvalds
*/
+
/*
- * console.c
- *
- * This module exports the console io functions:
- *
- * 'void do_keyboard_interrupt(void)'
- *
- * 'int vc_allocate(unsigned int console)'
- * 'int vc_cons_allocated(unsigned int console)'
- * 'int vc_resize(unsigned long lines, unsigned long cols)'
- * 'void vc_disallocate(unsigned int currcons)'
- *
- * 'unsigned long con_init(unsigned long)'
- * 'int con_open(struct tty_struct *tty, struct file * filp)'
- * 'void con_write(struct tty_struct * tty)'
- * 'void vt_console_print(const char * b)'
- * 'void update_screen(int new_console)'
- *
- * 'void do_blank_screen(int)'
- * 'void do_unblank_screen(void)'
- * 'void poke_blanked_console(void)'
- *
- * 'unsigned short *screen_pos(int currcons, int w_offset, int viewed)'
- * 'void complement_pos(int currcons, int offset)'
- * 'void invert_screen(int currcons, int offset, int count, int shift)'
- *
- * 'void scrollback(int lines)'
- * 'void scrollfront(int lines)'
- *
- * 'void mouse_report(struct tty_struct * tty, int butt, int mrx, int mry)'
- * 'int mouse_reporting(void)'
- *
* Hopefully this will be a rather complete VT102 implementation.
*
* Beeping thanks to John T Kohl.
@@ -63,38 +33,48 @@
* 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.Uytterhoeven@cs.kuleuven.ac.be>, Jan 1997.
+ *
+ * Original m68k console driver modifications by
+ *
+ * - Arno Griffioen <arno@usn.nl>
+ * - David Carter <carter@cs.bris.ac.uk>
+ *
+ * Note that the abstract console driver allows all consoles to be of
+ * potentially different sizes, so the following variables depend on the
+ * current console (currcons):
+ *
+ * - video_num_columns
+ * - video_num_lines
+ * - video_size_row
+ * - video_screen_size
+ * - can_do_color
+ *
+ * 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
*/
-#define BLANK 0x0020
-
-/* 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)
-
-/*
- * NOTE!!! We sometimes disable and enable interrupts for a short while
- * (to put a word in video IO), but this will work even for keyboard
- * interrupts. We know interrupts aren't enabled when getting a keyboard
- * interrupt, as we use trap-gates. Hopefully all is well.
- */
-
+#include <linux/module.h>
#include <linux/sched.h>
-#include <linux/timer.h>
-#include <linux/interrupt.h>
#include <linux/tty.h>
#include <linux/tty_flip.h>
-#include <linux/console.h>
-#include <linux/config.h>
#include <linux/kernel.h>
#include <linux/string.h>
#include <linux/errno.h>
@@ -102,112 +82,76 @@
#include <linux/malloc.h>
#include <linux/major.h>
#include <linux/mm.h>
-#include <linux/ioport.h>
+#include <linux/console.h>
#include <linux/init.h>
+#include <linux/vt_kern.h>
+#include <linux/selection.h>
+#include <linux/console_struct.h>
+#include <linux/kbd_kern.h>
+#include <linux/vt_kern.h>
+#include <linux/consolemap.h>
+#include <linux/timer.h>
+#include <linux/interrupt.h>
+#include <linux/config.h>
+#include <linux/version.h>
+#include <linux/tqueue.h>
#ifdef CONFIG_APM
#include <linux/apm_bios.h>
#endif
-#ifdef CONFIG_SGI
-#include <asm/sgialib.h>
-#elif defined(CONFIG_ACER_PICA_61)
-#include <asm/bootinfo.h>
-/*
- * The video control ports are mapped at virtual address
- * 0xe0200000 for the onboard S3 card of the Acer; M700 and Magnum 4000
- * don't have ports at all.
- */
-#define PORT_BASE video_port_base
-unsigned long video_port_base;
-#endif
#include <asm/io.h>
#include <asm/system.h>
#include <asm/uaccess.h>
-#include <asm/bitops.h>
-#include <linux/kbd_kern.h>
-#include <linux/vt_kern.h>
-#include <linux/consolemap.h>
-#include <linux/selection.h>
-#include <linux/console_struct.h>
+#include <asm/linux_logo.h>
-#ifndef MIN
-#define MIN(a,b) ((a) < (b) ? (a) : (b))
-#endif
+#include "console_macros.h"
+
+
+struct consw *conswitchp = NULL;
+
+static int vesa_blank_mode = 0; /* 0:none 1:suspendV 2:suspendH 3:powerdown */
+
+/* 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 */
-int serial_console;
+/*
+ * Here is the default bell parameters: 750HZ, 1/8th of a second
+ */
+#define DEFAULT_BELL_PITCH 750
+#define DEFAULT_BELL_DURATION (HZ/8)
-#ifdef __sparc__
-int serial_console;
+#ifndef MIN
+#define MIN(a,b) ((a) < (b) ? (a) : (b))
#endif
-struct tty_driver console_driver;
-static int console_refcount;
static struct tty_struct *console_table[MAX_NR_CONSOLES];
static struct termios *console_termios[MAX_NR_CONSOLES];
static struct termios *console_termios_locked[MAX_NR_CONSOLES];
-unsigned short *vc_scrbuf[MAX_NR_CONSOLES];
struct vc vc_cons [MAX_NR_CONSOLES];
static int con_open(struct tty_struct *, struct file *);
-static void con_setsize(unsigned long rows, unsigned long cols);
-static void vc_init(unsigned int console, unsigned long rows,
- unsigned long cols, int do_clear);
-extern void get_scrmem(int currcons);
-extern void set_scrmem(int currcons, long offset);
-static void set_origin(int currcons);
+static void vc_init(unsigned int console, unsigned int rows,
+ unsigned int cols, int do_clear);
static void blank_screen(void);
static void unblank_screen(void);
-extern void change_console(unsigned int);
-extern void poke_blanked_console(void);
static void gotoxy(int currcons, int new_x, int new_y);
static void save_cur(int currcons);
-extern void set_cursor(int currcons);
-extern void hide_cursor(void);
static void reset_terminal(int currcons, int do_clear);
-extern void reset_vc(unsigned int new_console);
-extern void vt_init(void);
-extern void set_vesa_blanking(unsigned long arg);
-extern void vesa_blank(void);
-extern void vesa_unblank(void);
-extern void vesa_powerdown(void);
-extern void compute_shiftstate(void);
-extern void reset_palette(int currcons);
-extern void set_palette(void);
-extern int con_is_present(void);
-extern unsigned long con_type_init(unsigned long, const char **);
-extern void con_type_init_finish(void);
-extern int set_get_cmap(unsigned char *, int);
-extern int set_get_font(unsigned char *, int, int);
-extern void rs_cons_hook(int chip, int out, int channel);
-
-/* Description of the hardware situation */
-unsigned char video_type; /* Type of display being used */
-unsigned long video_mem_base; /* Base of video memory */
-unsigned long video_mem_term; /* End of video memory */
-unsigned short video_port_reg; /* Video register select port */
-unsigned short video_port_val; /* Video register value port */
-unsigned long video_num_columns; /* Number of text columns */
-unsigned long video_num_lines; /* Number of text lines */
-unsigned long video_size_row;
-unsigned long video_screen_size;
-
-int can_do_color = 0;
+static void con_flush_chars(struct tty_struct *tty);
+
static int printable = 0; /* Is console ready for printing? */
-int video_mode_512ch = 0; /* 512-character mode */
-unsigned long video_font_height; /* Height of current screen font */
-unsigned long video_scan_lines; /* Number of scan lines on screen */
-static unsigned long default_font_height; /* Height of default screen font */
-int video_font_is_default = 1;
-static unsigned short console_charmask = 0x0ff;
+int do_poke_blanked_console = 0;
+int console_blanked = 0;
-/* used by kbd_bh - set by keyboard_interrupt */
- int do_poke_blanked_console = 0;
- int console_blanked = 0;
static int blankinterval = 10*60*HZ;
static int vesa_off_interval = 0;
-static long blank_origin, blank__origin, unblank_origin;
/*
* fg_console is the current virtual console,
@@ -220,270 +164,587 @@ int last_console = 0;
int want_console = -1;
int kmsg_redirect = 0;
-#ifdef CONFIG_SERIAL_ECHO
-
-#include <linux/serial_reg.h>
+/*
+ * 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 = NULL;
-extern int serial_echo_init (int base);
-extern int serial_echo_print (const char *s);
+/*
+ * 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 insert
+ * all filp requests to con_task_queue instead of tq_timer and run it from
+ * the console_bh.
+ */
+DECLARE_TASK_QUEUE(con_task_queue);
/*
- * this defines the address for the port to which printk echoing is done
- * when CONFIG_SERIAL_ECHO is defined
+ * Low-Level Functions
*/
-#define SERIAL_ECHO_PORT 0x3f8 /* COM1 */
-static int serial_echo_port = 0;
+#define IS_FG (currcons == fg_console)
+#define IS_VISIBLE (*display_fg == vc_cons[currcons].d)
-#define serial_echo_outb(v,a) outb((v),(a)+serial_echo_port)
-#define serial_echo_inb(a) inb((a)+serial_echo_port)
+#ifdef VT_BUF_VRAM_ONLY
+#define DO_UPDATE 0
+#else
+#define DO_UPDATE IS_VISIBLE
+#endif
-#define BOTH_EMPTY (UART_LSR_TEMT | UART_LSR_THRE)
+static inline unsigned short *screenpos(int currcons, int offset, int viewed)
+{
+ unsigned short *p = (unsigned short *)(visible_origin + offset);
+ return p;
+}
-/* Wait for transmitter & holding register to empty */
-#define WAIT_FOR_XMITR \
- do { \
- lsr = serial_echo_inb(UART_LSR); \
- } while ((lsr & BOTH_EMPTY) != BOTH_EMPTY)
+static void scrolldelta(int lines)
+{
+ int currcons = fg_console;
-/* These two functions abstract the actual communications with the
- * debug port. This is so we can change the underlying communications
- * mechanism without modifying the rest of the code.
+ clear_selection();
+ if (vcmode == KD_TEXT)
+ sw->con_scrolldelta(vc_cons[currcons].d, lines);
+}
+
+static void scrup(int currcons, unsigned int t, unsigned int b, int nr)
+{
+ unsigned short *d, *s;
+
+ if (t+nr >= b)
+ nr = b - t - 1;
+ if (b > video_num_lines || t >= b || nr < 1)
+ return;
+ if (IS_VISIBLE && sw->con_scroll(vc_cons[currcons].d, t, b, SM_UP, nr))
+ return;
+ d = (unsigned short *) (origin+video_size_row*t);
+ s = (unsigned short *) (origin+video_size_row*(t+nr));
+ scr_memcpyw(d, s, (b-t-nr) * video_size_row);
+ scr_memsetw(d + (b-t-nr) * video_num_columns, video_erase_char, video_size_row*nr);
+}
+
+static void
+scrdown(int currcons, unsigned int t, unsigned int b, int nr)
+{
+ unsigned short *s;
+ unsigned int step;
+
+ if (t+nr >= b)
+ nr = b - t - 1;
+ if (b > video_num_lines || t >= b || nr < 1)
+ return;
+ if (IS_VISIBLE && sw->con_scroll(vc_cons[currcons].d, t, b, SM_DOWN, nr))
+ return;
+ s = (unsigned short *) (origin+video_size_row*t);
+ step = video_num_columns * nr;
+ scr_memmovew(s + step, s, (b-t-nr)*video_size_row);
+ scr_memsetw(s, video_erase_char, 2*step);
+}
+
+static void do_update_region(int currcons, unsigned long start, int count)
+{
+#ifndef VT_BUF_VRAM_ONLY
+ unsigned int xx, yy, offset;
+ u16 *p;
+
+ if (start < origin) {
+ count -= origin - start;
+ start = origin;
+ }
+ if (count <= 0)
+ return;
+ offset = (start - origin) / 2;
+ xx = offset % video_num_columns;
+ yy = offset / video_num_columns;
+ p = (u16 *) start;
+ for(;;) {
+ u16 attrib = scr_readw(p) & 0xff00;
+ int startx = xx;
+ u16 *q = p;
+ while (xx < video_num_columns && count) {
+ if (attrib != (scr_readw(p) & 0xff00)) {
+ if (p > q)
+ sw->con_putcs(vc_cons[currcons].d, q, p-q, yy, startx);
+ startx = xx;
+ q = p;
+ attrib = scr_readw(p) & 0xff00;
+ }
+ p++;
+ xx++;
+ count--;
+ }
+ if (p > q)
+ sw->con_putcs(vc_cons[currcons].d, q, p-q, yy, startx);
+ if (!count)
+ break;
+ xx = 0;
+ yy++;
+ }
+#endif
+}
+
+void update_region(int currcons, unsigned long start, int count)
+{
+ if (DO_UPDATE)
+ do_update_region(currcons, start, count);
+}
+
+/* Structure of attributes is hardware-dependent */
+
+static u8 build_attr(int currcons, u8 _color, u8 _intensity, u8 _blink, u8 _underline, u8 _reverse)
+{
+ if (sw->con_build_attr)
+ return sw->con_build_attr(vc_cons[currcons].d, _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
*/
-int
-serial_echo_print(const char *s)
+ {
+ u8 a = color;
+ if (!can_do_color)
+ return _intensity |
+ (_underline ? 4 : 0) |
+ (_reverse ? 8 : 0) |
+ (_blink ? 0x80 : 0);
+ if (_underline)
+ a = (a & 0xf0) | ulcolor;
+ else if (_intensity == 0)
+ a = (a & 0xf0) | halfcolor;
+ if (_reverse)
+ a = ((a) & 0x88) | ((((a) >> 4) | ((a) << 4)) & 0x77);
+ if (_blink)
+ a ^= 0x80;
+ if (_intensity == 2)
+ a ^= 0x08;
+ if (hi_font_mask == 0x100)
+ a <<= 1;
+ return a;
+ }
+#else
+ return 0;
+#endif
+}
+
+static void update_attr(int currcons)
{
- int lsr, ier;
- int i;
+ attr = build_attr(currcons, color, intensity, blink, underline, reverse ^ decscnm);
+ video_erase_char = (build_attr(currcons, color, 1, 0, 0, decscnm) << 8) | ' ';
+}
- if (!serial_echo_port) return (0);
+/* Note: inverting the screen twice should revert to the original state */
- /*
- * First save the IER then disable the interrupts
- */
- ier = serial_echo_inb(UART_IER);
- serial_echo_outb(0x00, UART_IER);
+void invert_screen(int currcons, int offset, int count, int viewed)
+{
+ unsigned short *p;
- /*
- * Now, do each character
- */
- for (i = 0; *s; i++, s++) {
- WAIT_FOR_XMITR;
+ count /= 2;
+ p = screenpos(currcons, offset, viewed);
+ if (sw->con_invert_region)
+ sw->con_invert_region(vc_cons[currcons].d, p, count);
+#ifndef VT_BUF_VRAM_ONLY
+ else {
+ u16 *q = p;
+ int cnt = count;
+
+ if (!can_do_color) {
+ while (cnt--) *q++ ^= 0x0800;
+ } else if (hi_font_mask == 0x100) {
+ while (cnt--) {
+ u16 a = *q;
+ a = ((a) & 0x11ff) | (((a) & 0xe000) >> 4) | (((a) & 0x0e00) << 4);
+ *q++ = a;
+ }
+ } else {
+ while (cnt--) {
+ u16 a = *q;
+ a = ((a) & 0x88ff) | (((a) & 0x7000) >> 4) | (((a) & 0x0700) << 4);
+ *q++ = a;
+ }
+ }
+ }
+#endif
+ update_region(currcons, (unsigned long) p, count);
+}
- /* Send the character out. */
- serial_echo_outb(*s, UART_TX);
+/* used by selection: complement pointer position */
+void complement_pos(int currcons, int offset)
+{
+ static unsigned short *p = NULL;
+ static unsigned short old = 0;
+ static unsigned short oldx = 0, oldy = 0;
- /* if a LF, also do CR... */
- if (*s == 10) {
- WAIT_FOR_XMITR;
- serial_echo_outb(13, UART_TX);
+ if (p) {
+ scr_writew(old, p);
+ if (DO_UPDATE)
+ sw->con_putc(vc_cons[currcons].d, old, oldy, oldx);
+ }
+ if (offset == -1)
+ p = NULL;
+ else {
+ unsigned short new;
+ p = screenpos(currcons, offset, 1);
+ old = scr_readw(p);
+ new = old ^ complement_mask;
+ scr_writew(new, p);
+ if (DO_UPDATE) {
+ oldx = (offset >> 1) % video_num_columns;
+ oldy = (offset >> 1) / video_num_columns;
+ sw->con_putc(vc_cons[currcons].d, new, oldy, oldx);
}
}
+}
- /*
- * Finally, Wait for transmitter & holding register to empty
- * and restore the IER
- */
- do {
- lsr = serial_echo_inb(UART_LSR);
- } while ((lsr & BOTH_EMPTY) != BOTH_EMPTY);
- serial_echo_outb(ier, UART_IER);
+static void insert_char(int currcons, unsigned int nr)
+{
+ unsigned short *p, *q = (unsigned short *) pos;
- return (0);
+ p = q + video_num_columns - nr - x;
+ while (--p >= q)
+ scr_writew(scr_readw(p), p + nr);
+ scr_memsetw(q, video_erase_char, nr*2);
+ need_wrap = 0;
+ if (DO_UPDATE) {
+ unsigned short oldattr = attr;
+ sw->con_bmove(vc_cons[currcons].d,y,x,y,x+nr,1,
+ video_num_columns-x-nr);
+ attr = video_erase_char >> 8;
+ while (nr--)
+ sw->con_putc(vc_cons[currcons].d,
+ video_erase_char,y,x+nr);
+ attr = oldattr;
+ }
+}
+
+static void delete_char(int currcons, unsigned int nr)
+{
+ unsigned int i = x;
+ unsigned short *p = (unsigned short *) pos;
+
+ while (++i <= video_num_columns - nr) {
+ scr_writew(scr_readw(p+nr), p);
+ p++;
+ }
+ scr_memsetw(p, video_erase_char, nr*2);
+ need_wrap = 0;
+ if (DO_UPDATE) {
+ unsigned short oldattr = attr;
+ sw->con_bmove(vc_cons[currcons].d, y, x+nr, y, x, 1,
+ video_num_columns-x-nr);
+ attr = video_erase_char >> 8;
+ while (nr--)
+ sw->con_putc(vc_cons[currcons].d,
+ video_erase_char, y,
+ video_num_columns-1-nr);
+ attr = oldattr;
+ }
}
+static int softcursor_original;
-int
-serial_echo_init(int base)
+static void add_softcursor(int currcons)
{
- int comstat, hi, lo;
-
- if (base != 0x2f8 && base != 0x3f8) {
- serial_echo_port = 0;
- return (0);
- } else
- serial_echo_port = base;
+ int i = scr_readw((u16 *) pos);
+ u32 type = cursor_type;
- /*
- * read the Divisor Latch
- */
- comstat = serial_echo_inb(UART_LCR);
- serial_echo_outb(comstat | UART_LCR_DLAB, UART_LCR);
- hi = serial_echo_inb(UART_DLM);
- lo = serial_echo_inb(UART_DLL);
- serial_echo_outb(comstat, UART_LCR);
+ if (! (type & 0x10)) return;
+ if (softcursor_original != -1) return;
+ softcursor_original = i;
+ i |= ((type >> 8) & 0xff00 );
+ i ^= ((type) & 0xff00 );
+ if ((type & 0x20) && ((softcursor_original & 0x7000) == (i & 0x7000))) i ^= 0x7000;
+ if ((type & 0x40) && ((i & 0x700) == ((i & 0x7000) >> 4))) i ^= 0x0700;
+ scr_writew(i, (u16 *) pos);
+ if (DO_UPDATE)
+ sw->con_putc(vc_cons[currcons].d, i, y, x);
+}
- /*
- * now do hardwired init
- */
- serial_echo_outb(0x03, UART_LCR); /* No parity, 8 data bits, 1 stop */
- serial_echo_outb(0x83, UART_LCR); /* Access divisor latch */
- serial_echo_outb(0x00, UART_DLM); /* 9600 baud */
- serial_echo_outb(0x0c, UART_DLL);
- serial_echo_outb(0x03, UART_LCR); /* Done with divisor */
-
- /* Prior to disabling interrupts, read the LSR and RBR
- * registers
- */
- comstat = serial_echo_inb(UART_LSR); /* COM? LSR */
- comstat = serial_echo_inb(UART_RX); /* COM? RBR */
- serial_echo_outb(0x00, UART_IER); /* Disable all interrupts */
+static void hide_cursor(int currcons)
+{
+ if (currcons == sel_cons)
+ clear_selection();
+ if (softcursor_original != -1) {
+ scr_writew(softcursor_original,(u16 *) pos);
+ if (DO_UPDATE)
+ sw->con_putc(vc_cons[currcons].d, softcursor_original, y, x);
+ softcursor_original = -1;
+ }
+ sw->con_cursor(vc_cons[currcons].d,CM_ERASE);
+}
- return(0);
+void set_cursor(int currcons)
+{
+ if (!IS_FG || console_blanked || vcmode == KD_GRAPHICS)
+ return;
+ if (deccm) {
+ if (currcons == sel_cons)
+ clear_selection();
+ add_softcursor(currcons);
+ if ((cursor_type & 0x0f) != 1)
+ sw->con_cursor(vc_cons[currcons].d,CM_DRAW);
+ } else
+ hide_cursor(currcons);
+}
+
+static void set_origin(int currcons)
+{
+ if (!IS_VISIBLE ||
+ !sw->con_set_origin ||
+ !sw->con_set_origin(vc_cons[currcons].d))
+ origin = (unsigned long) screenbuf;
+ visible_origin = origin;
+ scr_end = origin + screenbuf_size;
+ pos = origin + video_size_row*y + 2*x;
+}
+
+static inline void save_screen(void)
+{
+ int currcons = fg_console;
+ if (sw->con_save_screen)
+ sw->con_save_screen(vc_cons[currcons].d);
+}
+
+/*
+ * Redrawing of screen
+ */
+
+void update_screen(int new_console)
+{
+ int currcons = fg_console;
+ int redraw = 1;
+ int old_console;
+ static int lock = 0;
+ struct vc_data **display;
+
+ if (lock)
+ return;
+ if (!vc_cons_allocated(new_console)) {
+ /* strange ... */
+ printk("update_screen: tty %d not allocated ??\n", new_console+1);
+ return;
+ }
+ lock = 1;
+
+ hide_cursor(currcons);
+ if (fg_console != new_console) {
+ display = vc_cons[new_console].d->vc_display_fg;
+ old_console = (*display) ? (*display)->vc_num : fg_console;
+ *display = vc_cons[new_console].d;
+ fg_console = new_console;
+ currcons = old_console;
+ if (!IS_VISIBLE)
+ set_origin(currcons);
+ currcons = new_console;
+ if (old_console == new_console)
+ redraw = 0;
+ }
+ if (redraw) {
+ set_origin(currcons);
+ if (sw->con_switch(vc_cons[currcons].d))
+ /* Update the screen contents */
+ do_update_region(currcons, origin, screenbuf_size/2);
+ }
+ set_cursor(currcons);
+ set_leds();
+ compute_shiftstate();
+ lock = 0;
}
-#endif /* CONFIG_SERIAL_ECHO */
+/*
+ * Allocation, freeing and resizing of VTs.
+ */
int vc_cons_allocated(unsigned int i)
{
return (i < MAX_NR_CONSOLES && vc_cons[i].d);
}
-int vc_allocate(unsigned int i) /* return 0 on success */
+void visual_init(int currcons)
+{
+ /* ++Geert: sw->con_init determines console size */
+ sw = conswitchp;
+ cons_num = currcons;
+ display_fg = &master_display_fg;
+ vc_cons[currcons].d->vc_uni_pagedir_loc = &vc_cons[currcons].d->vc_uni_pagedir;
+ vc_cons[currcons].d->vc_uni_pagedir = 0;
+ hi_font_mask = 0;
+ complement_mask = 0;
+ sw->con_init(vc_cons[currcons].d, 1);
+ if (!complement_mask)
+ complement_mask = can_do_color ? 0x7700 : 0x0800;
+ video_size_row = video_num_columns<<1;
+ video_screen_size = video_num_lines*video_size_row;
+}
+
+int vc_allocate(unsigned int currcons, int init) /* return 0 on success */
{
- if (i >= MAX_NR_CONSOLES)
+ if (currcons >= MAX_NR_CONSOLES)
return -ENXIO;
- if (!vc_cons[i].d) {
+ if (!vc_cons[currcons].d) {
long p, q;
/* prevent users from taking too much memory */
- if (i >= MAX_NR_USER_CONSOLES && !capable(CAP_SYS_RESOURCE))
+ if (currcons >= MAX_NR_USER_CONSOLES && !capable(CAP_SYS_RESOURCE))
return -EPERM;
/* due to the granularity of kmalloc, we waste some memory here */
/* the alloc is done in two steps, to optimize the common situation
of a 25x80 console (structsize=216, video_screen_size=4000) */
- q = (long) kmalloc(video_screen_size, GFP_KERNEL);
- if (!q)
- return -ENOMEM;
+ /* although the numbers above are not valid since long ago, the
+ point is still up-to-date and the comment still has its value
+ even if only as a historical artifact. --mj, July 1998 */
p = (long) kmalloc(structsize, GFP_KERNEL);
- if (!p) {
- kfree_s((char *) q, video_screen_size);
+ if (!p)
+ return -ENOMEM;
+ vc_cons[currcons].d = (struct vc_data *)p;
+ vt_cons[currcons] = (struct vt_struct *)(p+sizeof(struct vc_data));
+ visual_init(currcons);
+ q = (long)kmalloc(video_screen_size, GFP_KERNEL);
+ if (!q) {
+ kfree_s((char *) p, structsize);
+ vc_cons[currcons].d = NULL;
+ vt_cons[currcons] = NULL;
return -ENOMEM;
}
-
- vc_cons[i].d = (struct vc_data *) p;
- p += sizeof(struct vc_data);
- vt_cons[i] = (struct vt_struct *) p;
- vc_scrbuf[i] = (unsigned short *) q;
- vc_cons[i].d->vc_kmalloced = 1;
- vc_cons[i].d->vc_screenbuf_size = video_screen_size;
- vc_init (i, video_num_lines, video_num_columns, 1);
+ con_set_default_unimap(currcons);
+ screenbuf = (unsigned short *) q;
+ kmalloced = 1;
+ screenbuf_size = video_screen_size;
+ if (!sw->con_save_screen)
+ init = 0; /* If console does not have save_screen routine,
+ we should clear the screen */
+ vc_init(currcons, video_num_lines, video_num_columns, !init);
}
return 0;
}
/*
- * Change # of rows and columns (0 means unchanged)
+ * Change # of rows and columns (0 means unchanged/the size of fg_console)
* [this is to be used together with some user program
* like resize that changes the hardware videomode]
*/
-int vc_resize(unsigned long lines, unsigned long cols)
+int vc_resize(unsigned int lines, unsigned int cols,
+ unsigned int first, unsigned int last)
{
- unsigned long cc, ll, ss, sr;
- unsigned long occ, oll, oss, osr;
- unsigned short *p;
- unsigned int currcons, i;
+ unsigned int cc, ll, ss, sr, todo = 0;
+ unsigned int currcons = fg_console, i;
unsigned short *newscreens[MAX_NR_CONSOLES];
- long ol, nl, rlth, rrem;
cc = (cols ? cols : video_num_columns);
ll = (lines ? lines : video_num_lines);
sr = cc << 1;
ss = sr * ll;
- if (ss > video_mem_term - video_mem_base)
- return -ENOMEM;
-
- /*
- * Some earlier version had all consoles of potentially
- * different sizes, but that was really messy.
- * So now we only change if there is room for all consoles
- * of the same size.
- */
- for (currcons = 0; currcons < MAX_NR_CONSOLES; currcons++) {
- if (!vc_cons_allocated(currcons))
- newscreens[currcons] = 0;
- else {
- p = (unsigned short *) kmalloc(ss, GFP_USER);
- if (!p) {
- for (i = 0; i< currcons; i++)
- if (newscreens[i])
- kfree_s(newscreens[i], ss);
- return -ENOMEM;
+ for (currcons = first; currcons <= last; currcons++) {
+ if (!vc_cons_allocated(currcons) ||
+ (cc == video_num_columns && ll == video_num_lines))
+ newscreens[currcons] = NULL;
+ else {
+ unsigned short *p = (unsigned short *) kmalloc(ss, GFP_USER);
+ if (!p) {
+ for (i = 0; i< currcons; i++)
+ if (newscreens[i])
+ kfree_s(newscreens[i], ss);
+ return -ENOMEM;
+ }
+ newscreens[currcons] = p;
+ todo++;
}
- newscreens[currcons] = p;
- }
}
+ if (!todo)
+ return 0;
- get_scrmem(fg_console);
-
- oll = video_num_lines;
- occ = video_num_columns;
- osr = video_size_row;
- oss = video_screen_size;
-
- video_num_lines = ll;
- video_num_columns = cc;
- video_size_row = sr;
- video_screen_size = ss;
-
- for (currcons = 0; currcons < MAX_NR_CONSOLES; currcons++) {
- if (!vc_cons_allocated(currcons))
- continue;
-
- rlth = MIN(osr, sr);
- rrem = sr - rlth;
- ol = origin;
- nl = (long) newscreens[currcons];
- if (ll < oll)
- ol += (oll - ll) * osr;
-
- while (ol < scr_end) {
- memcpyw((unsigned short *) nl, (unsigned short *) ol, rlth);
- if (rrem)
- memsetw((void *)(nl + rlth), video_erase_char, rrem);
- ol += osr;
- nl += sr;
- }
-
- if (kmalloced)
- kfree_s(vc_scrbuf[currcons], screenbuf_size);
- vc_scrbuf[currcons] = newscreens[currcons];
- kmalloced = 1;
- screenbuf_size = ss;
+ for (currcons = first; currcons <= last; currcons++) {
+ unsigned int occ, oll, oss, osr;
+ unsigned long ol, nl, nlend, rlth, rrem;
+ if (!newscreens[currcons] || !vc_cons_allocated(currcons))
+ continue;
- origin = video_mem_start = (long) vc_scrbuf[currcons];
- scr_end = video_mem_end = video_mem_start + ss;
+ oll = video_num_lines;
+ occ = video_num_columns;
+ osr = video_size_row;
+ oss = video_screen_size;
+
+ video_num_lines = ll;
+ video_num_columns = cc;
+ video_size_row = sr;
+ video_screen_size = ss;
+
+ rlth = MIN(osr, sr);
+ rrem = sr - rlth;
+ ol = origin;
+ nl = (long) newscreens[currcons];
+ nlend = nl + ss;
+ if (ll < oll)
+ ol += (oll - ll) * osr;
+
+ update_attr(currcons);
+
+ while (ol < scr_end) {
+ scr_memcpyw((unsigned short *) nl, (unsigned short *) ol, rlth);
+ if (rrem)
+ scr_memsetw((void *)(nl + rlth), video_erase_char, rrem);
+ ol += osr;
+ nl += sr;
+ }
+ if (nlend > nl)
+ scr_memsetw((void *) nl, video_erase_char, nlend - nl);
+ if (kmalloced)
+ kfree_s(screenbuf, oss);
+ screenbuf = newscreens[currcons];
+ kmalloced = 1;
+ screenbuf_size = ss;
+ set_origin(currcons);
- if (scr_end > nl)
- memsetw((void *) nl, video_erase_char, scr_end - nl);
+ /* do part of a reset_terminal() */
+ top = 0;
+ bottom = video_num_lines;
+ gotoxy(currcons, x, y);
+ save_cur(currcons);
+
+ if (console_table[currcons]) {
+ struct winsize ws, *cws = &console_table[currcons]->winsize;
+ memset(&ws, 0, sizeof(ws));
+ ws.ws_row = video_num_lines;
+ ws.ws_col = video_num_columns;
+ if ((ws.ws_row != cws->ws_row || ws.ws_col != cws->ws_col) &&
+ console_table[currcons]->pgrp > 0)
+ kill_pg(console_table[currcons]->pgrp, SIGWINCH, 1);
+ *cws = ws;
+ }
- /* do part of a reset_terminal() */
- top = 0;
- bottom = video_num_lines;
- gotoxy(currcons, x, y);
- save_cur(currcons);
+ if (IS_FG && vt_cons[fg_console]->vc_mode == KD_TEXT)
+ update_screen(fg_console);
}
- set_scrmem(fg_console, 0);
- set_origin(fg_console);
set_cursor(fg_console);
-
return 0;
}
+
void vc_disallocate(unsigned int currcons)
{
if (vc_cons_allocated(currcons)) {
+ sw->con_deinit(vc_cons[currcons].d);
if (kmalloced)
- kfree_s(vc_scrbuf[currcons], screenbuf_size);
+ kfree_s(screenbuf, screenbuf_size);
if (currcons >= MIN_NR_CONSOLES)
- kfree_s(vc_cons[currcons].d, structsize);
- vc_cons[currcons].d = 0;
+ kfree_s(vc_cons[currcons].d, structsize);
+ vc_cons[currcons].d = NULL;
}
}
+/*
+ * VT102 emulator
+ */
#define set_kbd(x) set_vc_kbd_mode(kbd_table+currcons,x)
#define clr_kbd(x) clr_vc_kbd_mode(kbd_table+currcons,x)
@@ -550,61 +811,10 @@ static void gotoxay(int currcons, int new_x, int new_y)
gotoxy(currcons, new_x, decom ? (top+new_y) : new_y);
}
-/*
- * Hardware scrollback support
- */
-extern void __set_origin(unsigned short);
-unsigned short __real_origin; /* offset of non-scrolled screen */
-unsigned short __origin; /* offset of currently displayed screen */
-unsigned char has_wrapped; /* all of videomem is data of fg_console */
-static unsigned char hardscroll_enabled;
-static unsigned char hardscroll_disabled_by_init = 0;
-
-void no_scroll(char *str, int *ints)
-{
- /*
- * Disabling scrollback is required for the Braillex ib80-piezo
- * Braille reader made by F.H. Papenmeier (Germany).
- * Use the "no-scroll" bootflag.
- */
- hardscroll_disabled_by_init = 1;
- hardscroll_enabled = 0;
-}
-
-static void scrolldelta(int lines)
-{
- int new_origin;
- int last_origin_rel = (((video_mem_term - video_mem_base)
- / video_num_columns / 2) - (video_num_lines - 1)) * video_num_columns;
-
- new_origin = __origin + lines * video_num_columns;
- if (__origin > __real_origin)
- new_origin -= last_origin_rel;
- if (new_origin < 0) {
- int s_top = __real_origin + video_num_lines*video_num_columns;
- new_origin += last_origin_rel;
- if (new_origin < s_top)
- new_origin = s_top;
- if (new_origin > last_origin_rel - video_num_columns
- || has_wrapped == 0)
- new_origin = 0;
- else {
- unsigned short * d = (unsigned short *) video_mem_base;
- unsigned short * s = d + last_origin_rel;
- int count = (video_num_lines-1)*video_num_columns;
- while (count) {
- count--;
- scr_writew(scr_readw(d++),s++);
- }
- }
- } else if (new_origin > __real_origin)
- new_origin = __real_origin;
-
- __set_origin(new_origin);
-}
-
void scrollback(int lines)
{
+ int currcons = fg_console;
+
if (!lines)
lines = video_num_lines/2;
scrolldelta(-lines);
@@ -612,156 +822,20 @@ void scrollback(int lines)
void scrollfront(int lines)
{
+ int currcons = fg_console;
+
if (!lines)
lines = video_num_lines/2;
scrolldelta(lines);
}
-static void set_origin(int currcons)
-{
- if (video_type != VIDEO_TYPE_EGAC && video_type != VIDEO_TYPE_VGAC &&
- video_type != VIDEO_TYPE_EGAM && video_type != VIDEO_TYPE_PICA_S3 &&
- video_type != VIDEO_TYPE_SNI_RM && video_type != VIDEO_TYPE_SGI)
- return;
- if (currcons != fg_console || console_blanked || vcmode == KD_GRAPHICS)
- return;
- __real_origin = (origin-video_mem_base) >> 1;
- __set_origin(__real_origin);
-}
-
-static void scrup(int currcons, unsigned int t, unsigned int b, unsigned int nr)
-{
- int hardscroll = hardscroll_enabled;
-
- if (t+nr >= b)
- nr = b - t - 1;
- if (b > video_num_lines || t >= b || nr < 1)
- return;
- if (t || b != video_num_lines || nr > 1)
- hardscroll = 0;
- if (hardscroll) {
- origin += video_size_row;
- pos += video_size_row;
- scr_end += video_size_row;
-#if 0
- /*
- * Aiiiieee. This check works for Alpha and Intel, but
- * not for MIPS boxes ... The #ifdef is a temporary fix
- * for MIPSes that is slooow.
- */
- if (origin >= last_origin || origin < video_mem_base) { /*}*/
- if (scr_end > video_mem_end) { /*}*/
-#endif
- /*
- * Is the end of the area to scroll outside of the video RAM?
- * If so, just do normal softscroll. The second part of the
- * condition is important for some non-Intel architectures.
- */
- if (scr_end > video_mem_end || scr_end < video_mem_base) {
- unsigned short * d = (unsigned short *) video_mem_start;
- unsigned short * s = (unsigned short *) origin;
- unsigned int count;
-
- count = (video_num_lines-1)*video_num_columns;
- while (count) {
- count--;
- scr_writew(scr_readw(s++),d++);
- }
- count = video_num_columns;
- while (count) {
- count--;
- scr_writew(video_erase_char, d++);
- }
- scr_end -= origin-video_mem_start;
- pos -= origin-video_mem_start;
- origin = video_mem_start;
- has_scrolled = 1;
- if (currcons == fg_console)
- has_wrapped = 1;
- } else {
- unsigned short * d;
- unsigned int count;
-
- d = (unsigned short *) (scr_end - video_size_row);
- count = video_num_columns;
- while (count) {
- count--;
- scr_writew(video_erase_char, d++);
- }
- }
- set_origin(currcons);
- } else {
- unsigned short * d = (unsigned short *) (origin+video_size_row*t);
- unsigned short * s = (unsigned short *) (origin+video_size_row*(t+nr));
-
- memcpyw(d, s, (b-t-nr) * video_size_row);
- memsetw(d + (b-t-nr) * video_num_columns, video_erase_char, video_size_row*nr);
- }
-}
-
-static void
-scrdown(int currcons, unsigned int t, unsigned int b, unsigned int nr)
-{
- unsigned short *s;
- unsigned int count;
- unsigned int step;
-
- if (t+nr >= b)
- nr = b - t - 1;
- if (b > video_num_lines || t >= b || nr < 1)
- return;
- s = (unsigned short *) (origin+video_size_row*(b-nr-1));
- step = video_num_columns * nr;
- count = b - t - nr;
- while (count--) {
- memcpyw(s + step, s, video_size_row);
- s -= video_num_columns;
- }
- while (nr--) {
- s += video_num_columns;
- memsetw(s, video_erase_char, video_size_row);
- }
- has_scrolled = 1;
-}
-
-/*
- * Routine to reset the visible "screen" to the top of video memory.
- * This is necessary when exiting from the kernel back to a console
- * which expects only the top of video memory to be used for the visible
- * screen (with scrolling down by moving the memory contents).
- * The normal action of the LINUX console is to scroll using all of the
- * video memory and diddling the hardware top-of-video register as needed.
- */
-void
-scrreset(void)
-{
- int currcons = fg_console;
- unsigned short * d = (unsigned short *) video_mem_start;
- unsigned short * s = (unsigned short *) origin;
- unsigned int count;
-
- count = (video_num_lines-1)*video_num_columns;
- memcpyw(d, s, 2*count);
- memsetw(d + count, video_erase_char,
- 2*video_num_columns);
- scr_end -= origin-video_mem_start;
- pos -= origin-video_mem_start;
- origin = video_mem_start;
-
- has_scrolled = 1;
- has_wrapped = 1;
-
- set_origin(currcons);
- set_cursor(currcons);
-}
-
static void lf(int currcons)
{
/* don't scroll if above bottom of scrolling region, or
* if below scrolling region
*/
if (y+1 == bottom)
- scrup(currcons,top,bottom, 1);
+ scrup(currcons,top,bottom,1);
else if (y < video_num_lines-1) {
y++;
pos += video_size_row;
@@ -805,91 +879,96 @@ static inline void del(int currcons)
static void csi_J(int currcons, int vpar)
{
- unsigned long count;
+ unsigned int count;
unsigned short * start;
switch (vpar) {
case 0: /* erase from cursor to end of display */
count = (scr_end-pos)>>1;
start = (unsigned short *) pos;
+ if (DO_UPDATE) {
+ /* do in two stages */
+ sw->con_clear(vc_cons[currcons].d, y, x, 1,
+ video_num_columns-x);
+ sw->con_clear(vc_cons[currcons].d, y+1, 0,
+ video_num_lines-y-1,
+ video_num_columns);
+ }
break;
case 1: /* erase from start to cursor */
count = ((pos-origin)>>1)+1;
start = (unsigned short *) origin;
+ if (DO_UPDATE) {
+ /* do in two stages */
+ sw->con_clear(vc_cons[currcons].d, 0, 0, y,
+ video_num_columns);
+ sw->con_clear(vc_cons[currcons].d, y, 0, 1,
+ x + 1);
+ }
break;
case 2: /* erase whole display */
count = video_num_columns * video_num_lines;
start = (unsigned short *) origin;
+ if (DO_UPDATE)
+ sw->con_clear(vc_cons[currcons].d, 0, 0,
+ video_num_lines,
+ video_num_columns);
break;
default:
return;
}
- memsetw(start, video_erase_char, 2*count);
+ scr_memsetw(start, video_erase_char, 2*count);
need_wrap = 0;
}
static void csi_K(int currcons, int vpar)
{
- unsigned long count;
+ unsigned int count;
unsigned short * start;
switch (vpar) {
case 0: /* erase from cursor to end of line */
count = video_num_columns-x;
start = (unsigned short *) pos;
+ if (DO_UPDATE)
+ sw->con_clear(vc_cons[currcons].d, y, x, 1,
+ video_num_columns-x);
break;
case 1: /* erase from start of line to cursor */
start = (unsigned short *) (pos - (x<<1));
count = x+1;
+ if (DO_UPDATE)
+ sw->con_clear(vc_cons[currcons].d, y, 0, 1,
+ x + 1);
break;
case 2: /* erase whole line */
start = (unsigned short *) (pos - (x<<1));
count = video_num_columns;
+ if (DO_UPDATE)
+ sw->con_clear(vc_cons[currcons].d, y, 0, 1,
+ video_num_columns);
break;
default:
return;
}
- memsetw(start, video_erase_char, 2 * count);
+ scr_memsetw(start, video_erase_char, 2 * count);
need_wrap = 0;
}
static void csi_X(int currcons, int vpar) /* erase the following vpar positions */
{ /* not vt100? */
+ int count;
+
if (!vpar)
vpar++;
+ count = (vpar > video_num_columns-x) ? (video_num_columns-x) : vpar;
- memsetw((unsigned short *) pos, video_erase_char,
- (vpar > video_num_columns-x) ? 2 * (video_num_columns-x) : 2 * vpar);
+ scr_memsetw((unsigned short *) pos, video_erase_char, 2 * count);
+ if (DO_UPDATE)
+ sw->con_clear(vc_cons[currcons].d, y, x, 1, count);
need_wrap = 0;
}
-static void update_attr(int currcons)
-{
- attr = color;
- if (can_do_color) {
- if (underline)
- attr = (attr & 0xf0) | ulcolor;
- else if (intensity == 0)
- attr = (attr & 0xf0) | halfcolor;
- }
- if (reverse ^ decscnm)
- attr = reverse_video_char(attr);
- if (blink)
- attr ^= 0x80;
- if (intensity == 2)
- attr ^= 0x08;
- if (!can_do_color) {
- if (underline)
- attr = (attr & 0xf8) | 0x01;
- else if (intensity == 0)
- attr = (attr & 0xf0) | 0x08;
- }
- if (decscnm)
- video_erase_char = (reverse_video_char(color) << 8) | ' ';
- else
- video_erase_char = (color << 8) | ' ';
-}
-
static void default_attr(int currcons)
{
intensity = 1;
@@ -1000,14 +1079,14 @@ static void respond_string(const char * p, struct tty_struct * tty)
tty_insert_flip_char(tty, *p, 0);
p++;
}
- tty_schedule_flip(tty);
+ con_schedule_flip(tty);
}
static void cursor_report(int currcons, struct tty_struct * tty)
{
char buf[40];
- sprintf(buf, "\033[%ld;%ldR", y + (decom ? top+1 : 1), x+1);
+ sprintf(buf, "\033[%d;%dR", y + (decom ? top+1 : 1), x+1);
respond_string(buf, tty);
}
@@ -1038,135 +1117,6 @@ int mouse_reporting(void)
return report_mouse;
}
-int tioclinux(struct tty_struct *tty, unsigned long arg)
-{
- char type, data;
-
- if (tty->driver.type != TTY_DRIVER_TYPE_CONSOLE)
- return -EINVAL;
- if (current->tty != tty && !suser())
- return -EPERM;
- if (get_user(type, (char *)arg))
- return -EFAULT;
- switch (type)
- {
- case 2:
- return set_selection(arg, tty, 1);
- case 3:
- return paste_selection(tty);
- case 4:
- do_unblank_screen();
- return 0;
- case 5:
- return sel_loadlut(arg);
- case 6:
-
- /*
- * Make it possible to react to Shift+Mousebutton.
- * Note that 'shift_state' is an undocumented
- * kernel-internal variable; programs not closely
- * related to the kernel should not use this.
- */
- data = shift_state;
- return __put_user(data, (char *) arg);
- case 7:
- data = mouse_reporting();
- return __put_user(data, (char *) arg);
- case 10:
- set_vesa_blanking(arg);
- return 0;
- case 11: /* set kmsg redirect */
- if (!suser())
- return -EPERM;
- if (get_user(data, (char *)arg+1))
- return -EFAULT;
- kmsg_redirect = data;
- return 0;
- case 12: /* get fg_console */
- return fg_console;
- }
- return -EINVAL;
-}
-
-static inline unsigned short *screenpos(int currcons, int offset, int viewed)
-{
- unsigned short *p = (unsigned short *)(origin + offset);
- if (viewed && currcons == fg_console)
- p -= (__real_origin - __origin);
- return p;
-}
-
-/* Note: inverting the screen twice should revert to the original state */
-void invert_screen(int currcons, int offset, int count, int viewed)
-{
- unsigned short *p;
-
- count /= 2;
- p = screenpos(currcons, offset, viewed);
- if (can_do_color)
- while (count--) {
- unsigned short old = scr_readw(p);
- scr_writew(reverse_video_short(old), p);
- p++;
- }
- else
- while (count--) {
- unsigned short old = scr_readw(p);
- scr_writew(old ^ (((old & 0x0700) == 0x0100)
- ? 0x7000 : 0x7700), p);
- p++;
- }
-}
-
-/* used by selection: complement pointer position */
-void complement_pos(int currcons, int offset)
-{
- static unsigned short *p = NULL;
- static unsigned short old = 0;
-
- if (p)
- scr_writew(old, p);
- if (offset == -1)
- p = NULL;
- else {
- p = screenpos(currcons, offset, 1);
- old = scr_readw(p);
- scr_writew(old ^ 0x7700, p);
- }
-}
-
-/* used by selection */
-unsigned short screen_word(int currcons, int offset, int viewed)
-{
- return scr_readw(screenpos(currcons, offset, viewed));
-}
-
-/* used by selection - convert a screen word to a glyph number */
-int scrw2glyph(unsigned short scr_word)
-{
- return ( video_mode_512ch )
- ? ((scr_word & 0x0800) >> 3) + (scr_word & 0x00ff)
- : scr_word & 0x00ff;
-}
-
-/* used by vcs - note the word offset */
-unsigned short *screen_pos(int currcons, int w_offset, int viewed)
-{
- return screenpos(currcons, 2 * w_offset, viewed);
-}
-
-void getconsxy(int currcons, char *p)
-{
- p[0] = x;
- p[1] = y;
-}
-
-void putconsxy(int currcons, char *p)
-{
- gotoxy(currcons, p[0], p[1]);
- set_cursor(currcons);
-}
-
static void set_mode(int currcons, int on_off)
{
int i;
@@ -1212,7 +1162,6 @@ static void set_mode(int currcons, int on_off)
break;
case 25: /* Cursor on/off */
deccm = on_off;
- set_cursor(currcons);
break;
case 1000:
report_mouse = on_off ? 2 : 0;
@@ -1274,10 +1223,10 @@ static void setterm_command(int currcons)
break;
case 12: /* bring specified console to the front */
if (par[1] >= 1 && vc_cons_allocated(par[1]-1))
- update_screen(par[1]-1);
+ set_console(par[1] - 1);
break;
case 13: /* unblank the screen */
- unblank_screen();
+ poke_blanked_console();
break;
case 14: /* set vesa powerdown interval */
vesa_off_interval = ((par[1] < 60) ? par[1] : 60) * 60 * HZ;
@@ -1285,39 +1234,12 @@ static void setterm_command(int currcons)
}
}
-static void insert_char(int currcons)
-{
- unsigned int i = x;
- unsigned short tmp, old = video_erase_char;
- unsigned short * p = (unsigned short *) pos;
-
- while (i++ < video_num_columns) {
- tmp = scr_readw(p);
- scr_writew(old, p);
- old = tmp;
- p++;
- }
- need_wrap = 0;
-}
-
static void insert_line(int currcons, unsigned int nr)
{
scrdown(currcons,y,bottom,nr);
need_wrap = 0;
}
-static void delete_char(int currcons)
-{
- unsigned int i = x;
- unsigned short * p = (unsigned short *) pos;
-
- while (++i < video_num_columns) {
- scr_writew(scr_readw(p+1), p);
- p++;
- }
- scr_writew(video_erase_char, p);
- need_wrap = 0;
-}
static void delete_line(int currcons, unsigned int nr)
{
@@ -1327,18 +1249,17 @@ static void delete_line(int currcons, unsigned int nr)
static void csi_at(int currcons, unsigned int nr)
{
- if (nr > video_num_columns)
- nr = video_num_columns;
+ if (nr > video_num_columns - x)
+ nr = video_num_columns - x;
else if (!nr)
nr = 1;
- while (nr--)
- insert_char(currcons);
+ insert_char(currcons, nr);
}
static void csi_L(int currcons, unsigned int nr)
{
- if (nr > video_num_lines)
- nr = video_num_lines;
+ if (nr > video_num_lines - y)
+ nr = video_num_lines - y;
else if (!nr)
nr = 1;
insert_line(currcons, nr);
@@ -1346,18 +1267,17 @@ static void csi_L(int currcons, unsigned int nr)
static void csi_P(int currcons, unsigned int nr)
{
- if (nr > video_num_columns)
- nr = video_num_columns;
+ if (nr > video_num_columns - x)
+ nr = video_num_columns - x;
else if (!nr)
nr = 1;
- while (nr--)
- delete_char(currcons);
+ delete_char(currcons, nr);
}
static void csi_M(int currcons, unsigned int nr)
{
- if (nr > video_num_lines)
- nr = video_num_lines;
+ if (nr > video_num_lines - y)
+ nr = video_num_lines - y;
else if (!nr)
nr=1;
delete_line(currcons, nr);
@@ -1431,6 +1351,8 @@ static void reset_terminal(int currcons, int do_clear)
kbd_table[currcons].ledflagstate = kbd_table[currcons].default_ledflagstate;
set_leds();
+ cursor_type = CUR_DEFAULT;
+
default_attr(currcons);
update_attr(currcons);
@@ -1449,61 +1371,380 @@ static void reset_terminal(int currcons, int do_clear)
csi_J(currcons,2);
}
-/*
- * Turn the Scroll-Lock LED on when the tty is stopped
- */
-static void con_stop(struct tty_struct *tty)
+static void do_con_trol(struct tty_struct *tty, unsigned int currcons, int c)
{
- int console_num;
- if (!tty)
+ /*
+ * Control characters can be used in the _middle_
+ * of an escape sequence.
+ */
+ switch (c) {
+ case 0:
return;
- console_num = MINOR(tty->device) - (tty->driver.minor_start);
- if (!vc_cons_allocated(console_num))
+ case 7:
+ if (bell_duration)
+ kd_mksound(bell_pitch, bell_duration);
return;
-#if !CONFIG_AP1000
- set_vc_kbd_led(kbd_table + console_num, VC_SCROLLOCK);
- set_leds();
-#endif
-}
-
-/*
- * Turn the Scroll-Lock LED off when the console is started
- */
-static void con_start(struct tty_struct *tty)
-{
- int console_num;
- if (!tty)
+ case 8:
+ bs(currcons);
return;
- console_num = MINOR(tty->device) - (tty->driver.minor_start);
- if (!vc_cons_allocated(console_num))
+ case 9:
+ pos -= (x << 1);
+ while (x < video_num_columns - 1) {
+ x++;
+ if (tab_stop[x >> 5] & (1 << (x & 31)))
+ break;
+ }
+ pos += (x << 1);
return;
-#if !CONFIG_AP1000
- clr_vc_kbd_led(kbd_table + console_num, VC_SCROLLOCK);
- set_leds();
-#endif
+ case 10: case 11: case 12:
+ lf(currcons);
+ if (!is_kbd(lnm))
+ return;
+ case 13:
+ cr(currcons);
+ return;
+ case 14:
+ charset = 1;
+ translate = set_translate(G1_charset);
+ disp_ctrl = 1;
+ return;
+ case 15:
+ charset = 0;
+ translate = set_translate(G0_charset);
+ disp_ctrl = 0;
+ return;
+ case 24: case 26:
+ vc_state = ESnormal;
+ return;
+ case 27:
+ vc_state = ESesc;
+ return;
+ case 127:
+ del(currcons);
+ return;
+ case 128+27:
+ vc_state = ESsquare;
+ return;
+ }
+ switch(vc_state) {
+ case ESesc:
+ vc_state = ESnormal;
+ switch (c) {
+ case '[':
+ vc_state = ESsquare;
+ return;
+ case ']':
+ vc_state = ESnonstd;
+ return;
+ case '%':
+ vc_state = ESpercent;
+ return;
+ case 'E':
+ cr(currcons);
+ lf(currcons);
+ return;
+ case 'M':
+ ri(currcons);
+ return;
+ case 'D':
+ lf(currcons);
+ return;
+ case 'H':
+ tab_stop[x >> 5] |= (1 << (x & 31));
+ return;
+ case 'Z':
+ respond_ID(tty);
+ return;
+ case '7':
+ save_cur(currcons);
+ return;
+ case '8':
+ restore_cur(currcons);
+ return;
+ case '(':
+ vc_state = ESsetG0;
+ return;
+ case ')':
+ vc_state = ESsetG1;
+ return;
+ case '#':
+ vc_state = EShash;
+ return;
+ case 'c':
+ reset_terminal(currcons,1);
+ return;
+ case '>': /* Numeric keypad */
+ clr_kbd(kbdapplic);
+ return;
+ case '=': /* Appl. keypad */
+ set_kbd(kbdapplic);
+ return;
+ }
+ return;
+ case ESnonstd:
+ if (c=='P') { /* palette escape sequence */
+ for (npar=0; npar<NPAR; npar++)
+ par[npar] = 0 ;
+ npar = 0 ;
+ vc_state = ESpalette;
+ return;
+ } else if (c=='R') { /* reset palette */
+ reset_palette (currcons);
+ vc_state = ESnormal;
+ } else
+ vc_state = ESnormal;
+ return;
+ case ESpalette:
+ if ( (c>='0'&&c<='9') || (c>='A'&&c<='F') || (c>='a'&&c<='f') ) {
+ par[npar++] = (c>'9' ? (c&0xDF)-'A'+10 : c-'0') ;
+ if (npar==7) {
+ int i = par[0]*3, j = 1;
+ palette[i] = 16*par[j++];
+ palette[i++] += par[j++];
+ palette[i] = 16*par[j++];
+ palette[i++] += par[j++];
+ palette[i] = 16*par[j++];
+ palette[i] += par[j];
+ set_palette() ;
+ vc_state = ESnormal;
+ }
+ } else
+ vc_state = ESnormal;
+ return;
+ case ESsquare:
+ for(npar = 0 ; npar < NPAR ; npar++)
+ par[npar] = 0;
+ npar = 0;
+ vc_state = ESgetpars;
+ if (c == '[') { /* Function key */
+ vc_state=ESfunckey;
+ return;
+ }
+ ques = (c=='?');
+ if (ques)
+ return;
+ case ESgetpars:
+ if (c==';' && npar<NPAR-1) {
+ npar++;
+ return;
+ } else if (c>='0' && c<='9') {
+ par[npar] *= 10;
+ par[npar] += c-'0';
+ return;
+ } else vc_state=ESgotpars;
+ case ESgotpars:
+ vc_state = ESnormal;
+ switch(c) {
+ case 'h':
+ set_mode(currcons,1);
+ return;
+ case 'l':
+ set_mode(currcons,0);
+ return;
+ case 'c':
+ if (ques) {
+ if (par[0])
+ cursor_type = par[0] | (par[1]<<8) | (par[2]<<16);
+ else
+ cursor_type = CUR_DEFAULT;
+ return;
+ }
+ break;
+ case 'n':
+ if (!ques) {
+ if (par[0] == 5)
+ status_report(tty);
+ else if (par[0] == 6)
+ cursor_report(currcons,tty);
+ }
+ return;
+ }
+ if (ques) {
+ ques = 0;
+ return;
+ }
+ switch(c) {
+ case 'G': case '`':
+ if (par[0]) par[0]--;
+ gotoxy(currcons,par[0],y);
+ return;
+ case 'A':
+ if (!par[0]) par[0]++;
+ gotoxy(currcons,x,y-par[0]);
+ return;
+ case 'B': case 'e':
+ if (!par[0]) par[0]++;
+ gotoxy(currcons,x,y+par[0]);
+ return;
+ case 'C': case 'a':
+ if (!par[0]) par[0]++;
+ gotoxy(currcons,x+par[0],y);
+ return;
+ case 'D':
+ if (!par[0]) par[0]++;
+ gotoxy(currcons,x-par[0],y);
+ return;
+ case 'E':
+ if (!par[0]) par[0]++;
+ gotoxy(currcons,0,y+par[0]);
+ return;
+ case 'F':
+ if (!par[0]) par[0]++;
+ gotoxy(currcons,0,y-par[0]);
+ return;
+ case 'd':
+ if (par[0]) par[0]--;
+ gotoxay(currcons,x,par[0]);
+ return;
+ case 'H': case 'f':
+ if (par[0]) par[0]--;
+ if (par[1]) par[1]--;
+ gotoxay(currcons,par[1],par[0]);
+ return;
+ case 'J':
+ csi_J(currcons,par[0]);
+ return;
+ case 'K':
+ csi_K(currcons,par[0]);
+ return;
+ case 'L':
+ csi_L(currcons,par[0]);
+ return;
+ case 'M':
+ csi_M(currcons,par[0]);
+ return;
+ case 'P':
+ csi_P(currcons,par[0]);
+ return;
+ case 'c':
+ if (!par[0])
+ respond_ID(tty);
+ return;
+ case 'g':
+ if (!par[0])
+ tab_stop[x >> 5] &= ~(1 << (x & 31));
+ else if (par[0] == 3) {
+ tab_stop[0] =
+ tab_stop[1] =
+ tab_stop[2] =
+ tab_stop[3] =
+ tab_stop[4] = 0;
+ }
+ return;
+ case 'm':
+ csi_m(currcons);
+ return;
+ case 'q': /* DECLL - but only 3 leds */
+ /* map 0,1,2,3 to 0,1,2,4 */
+ if (par[0] < 4)
+ setledstate(kbd_table + currcons,
+ (par[0] < 3) ? par[0] : 4);
+ return;
+ case 'r':
+ if (!par[0])
+ par[0]++;
+ if (!par[1])
+ par[1] = video_num_lines;
+ /* Minimum allowed region is 2 lines */
+ if (par[0] < par[1] &&
+ par[1] <= video_num_lines) {
+ top=par[0]-1;
+ bottom=par[1];
+ gotoxay(currcons,0,0);
+ }
+ return;
+ case 's':
+ save_cur(currcons);
+ return;
+ case 'u':
+ restore_cur(currcons);
+ return;
+ case 'X':
+ csi_X(currcons, par[0]);
+ return;
+ case '@':
+ csi_at(currcons,par[0]);
+ return;
+ case ']': /* setterm functions */
+ setterm_command(currcons);
+ return;
+ }
+ return;
+ case ESpercent:
+ vc_state = ESnormal;
+ switch (c) {
+ case '@': /* defined in ISO 2022 */
+ utf = 0;
+ return;
+ case 'G': /* prelim official escape code */
+ case '8': /* retained for compatibility */
+ utf = 1;
+ return;
+ }
+ return;
+ case ESfunckey:
+ vc_state = ESnormal;
+ return;
+ case EShash:
+ vc_state = ESnormal;
+ if (c == '8') {
+ /* DEC screen alignment test. kludge :-) */
+ video_erase_char =
+ (video_erase_char & 0xff00) | 'E';
+ csi_J(currcons, 2);
+ video_erase_char =
+ (video_erase_char & 0xff00) | ' ';
+ do_update_region(currcons, origin, screenbuf_size/2);
+ }
+ return;
+ case ESsetG0:
+ if (c == '0')
+ G0_charset = GRAF_MAP;
+ else if (c == 'B')
+ G0_charset = LAT1_MAP;
+ else if (c == 'U')
+ G0_charset = IBMPC_MAP;
+ else if (c == 'K')
+ G0_charset = USER_MAP;
+ if (charset == 0)
+ translate = set_translate(G0_charset);
+ vc_state = ESnormal;
+ return;
+ case ESsetG1:
+ if (c == '0')
+ G1_charset = GRAF_MAP;
+ else if (c == 'B')
+ G1_charset = LAT1_MAP;
+ else if (c == 'U')
+ G1_charset = IBMPC_MAP;
+ else if (c == 'K')
+ G1_charset = USER_MAP;
+ if (charset == 1)
+ translate = set_translate(G1_charset);
+ vc_state = ESnormal;
+ return;
+ default:
+ vc_state = ESnormal;
+ }
}
-static void con_flush_chars(struct tty_struct *tty)
-{
- unsigned int currcons;
- struct vt_struct *vt = (struct vt_struct *)tty->driver_data;
-
- currcons = vt->vc_num;
- if (vcmode != KD_GRAPHICS)
- set_cursor(currcons);
-}
-
static int do_con_write(struct tty_struct * tty, int from_user,
const unsigned char *buf, int count)
{
- int c, tc, ok, n = 0;
+#ifdef VT_BUF_VRAM_ONLY
+#define FLUSH do { } while(0);
+#else
+#define FLUSH if (draw_x >= 0) { \
+ sw->con_putcs(vc_cons[currcons].d, (u16 *)draw_from, (u16 *)draw_to-(u16 *)draw_from, y, draw_x); \
+ draw_x = -1; \
+ }
+#endif
+
+ int c, tc, ok, n = 0, draw_x = -1;
unsigned int currcons;
+ unsigned long draw_from = 0, draw_to = 0;
struct vt_struct *vt = (struct vt_struct *)tty->driver_data;
-
-#if CONFIG_AP1000
- ap_write(1,buf,count);
- return(count);
-#endif
+ u16 himask, charmask;
currcons = vt->vc_num;
if (!vc_cons_allocated(currcons)) {
@@ -1516,17 +1757,21 @@ static int do_con_write(struct tty_struct * tty, int from_user,
return 0;
}
- if (currcons == sel_cons)
- clear_selection();
-
if (from_user) {
/* just to make sure that noone lurks at places he shouldn't see. */
if (verify_area(VERIFY_READ, buf, count))
return 0; /* ?? are error codes legal here ?? */
}
+ himask = hi_font_mask;
+ charmask = himask ? 0x1ff : 0xff;
+
+ /* undraw cursor first */
+ if (IS_FG)
+ hide_cursor(currcons);
+
disable_bh(CONSOLE_BH);
- while (!tty->stopped && count) {
+ while (!tty->stopped && count) {
enable_bh(CONSOLE_BH);
if (from_user)
__get_user(c, buf);
@@ -1591,11 +1836,11 @@ static int do_con_write(struct tty_struct * tty, int from_user,
if (vc_state == ESnormal && ok) {
/* Now try to find out how to display it */
- tc = conv_uni_to_pc(tc);
+ tc = conv_uni_to_pc(vc_cons[currcons].d, tc);
if ( tc == -4 ) {
/* If we got -4 (not found) then see if we have
defined a replacement character (U+FFFD) */
- tc = conv_uni_to_pc(0xfffd);
+ tc = conv_uni_to_pc(vc_cons[currcons].d, 0xfffd);
/* One reason for the -4 can be that we just
did a clear_unimap();
@@ -1606,429 +1851,86 @@ static int do_con_write(struct tty_struct * tty, int from_user,
/* Bad hash table -- hope for the best */
tc = c;
}
- if (tc & ~console_charmask)
+ if (tc & ~charmask)
continue; /* Conversion failed */
+ if (need_wrap || decim)
+ FLUSH
if (need_wrap) {
cr(currcons);
lf(currcons);
}
if (decim)
- insert_char(currcons);
- scr_writew( video_mode_512ch ?
- ((attr & 0xf7) << 8) + ((tc & 0x100) << 3) +
- (tc & 0x0ff) : (attr << 8) + tc,
- (unsigned short *) pos);
- if (x == video_num_columns - 1)
+ insert_char(currcons, 1);
+ scr_writew(himask ?
+ ((attr & ~himask) << 8) + ((tc & 0x100) ? himask : 0) + (tc & 0xff) :
+ (attr << 8) + tc,
+ (u16 *) pos);
+ if (DO_UPDATE && draw_x < 0) {
+ draw_x = x;
+ draw_from = pos;
+ }
+ if (x == video_num_columns - 1) {
need_wrap = decawm;
- else {
+ draw_to = pos+2;
+ } else {
x++;
- pos+=2;
+ draw_to = (pos+=2);
}
continue;
}
-
- /*
- * Control characters can be used in the _middle_
- * of an escape sequence.
- */
- switch (c) {
- case 0:
- continue;
- case 7:
- if (bell_duration)
- kd_mksound(bell_pitch, bell_duration);
- continue;
- case 8:
- bs(currcons);
- continue;
- case 9:
- pos -= (x << 1);
- while (x < video_num_columns - 1) {
- x++;
- if (tab_stop[x >> 5] & (1 << (x & 31)))
- break;
- }
- pos += (x << 1);
- continue;
- case 10: case 11: case 12:
- lf(currcons);
- if (!is_kbd(lnm))
- continue;
- case 13:
- cr(currcons);
- continue;
- case 14:
- charset = 1;
- translate = set_translate(G1_charset);
- disp_ctrl = 1;
- continue;
- case 15:
- charset = 0;
- translate = set_translate(G0_charset);
- disp_ctrl = 0;
- continue;
- case 24: case 26:
- vc_state = ESnormal;
- continue;
- case 27:
- vc_state = ESesc;
- continue;
- case 127:
- del(currcons);
- continue;
- case 128+27:
- vc_state = ESsquare;
- continue;
- }
- switch(vc_state) {
- case ESesc:
- vc_state = ESnormal;
- switch (c) {
- case '[':
- vc_state = ESsquare;
- continue;
- case ']':
- vc_state = ESnonstd;
- continue;
- case '%':
- vc_state = ESpercent;
- continue;
- case 'E':
- cr(currcons);
- lf(currcons);
- continue;
- case 'M':
- ri(currcons);
- continue;
- case 'D':
- lf(currcons);
- continue;
- case 'H':
- tab_stop[x >> 5] |= (1 << (x & 31));
- continue;
- case 'Z':
- respond_ID(tty);
- continue;
- case '7':
- save_cur(currcons);
- continue;
- case '8':
- restore_cur(currcons);
- continue;
- case '(':
- vc_state = ESsetG0;
- continue;
- case ')':
- vc_state = ESsetG1;
- continue;
- case '#':
- vc_state = EShash;
- continue;
- case 'c':
- reset_terminal(currcons,1);
- continue;
- case '>': /* Numeric keypad */
- clr_kbd(kbdapplic);
- continue;
- case '=': /* Appl. keypad */
- set_kbd(kbdapplic);
- continue;
- }
- continue;
- case ESnonstd:
- if (c=='P') { /* palette escape sequence */
- for (npar=0; npar<NPAR; npar++)
- par[npar] = 0 ;
- npar = 0 ;
- vc_state = ESpalette;
- continue;
- } else if (c=='R') { /* reset palette */
- reset_palette (currcons);
- vc_state = ESnormal;
- } else
- vc_state = ESnormal;
- continue;
- case ESpalette:
- if ( (c>='0'&&c<='9') || (c>='A'&&c<='F') || (c>='a'&&c<='f') ) {
- par[npar++] = (c>'9' ? (c&0xDF)-'A'+10 : c-'0') ;
- if (npar==7) {
- int i = par[0]*3, j = 1;
- palette[i] = 16*par[j++];
- palette[i++] += par[j++];
- palette[i] = 16*par[j++];
- palette[i++] += par[j++];
- palette[i] = 16*par[j++];
- palette[i] += par[j];
- set_palette() ;
- vc_state = ESnormal;
- }
- } else
- vc_state = ESnormal;
- continue;
- case ESsquare:
- for(npar = 0 ; npar < NPAR ; npar++)
- par[npar] = 0;
- npar = 0;
- vc_state = ESgetpars;
- if (c == '[') { /* Function key */
- vc_state=ESfunckey;
- continue;
- }
- ques = (c=='?');
- if (ques)
- continue;
- case ESgetpars:
- if (c==';' && npar<NPAR-1) {
- npar++;
- continue;
- } else if (c>='0' && c<='9') {
- par[npar] *= 10;
- par[npar] += c-'0';
- continue;
- } else vc_state=ESgotpars;
- case ESgotpars:
- vc_state = ESnormal;
- switch(c) {
- case 'h':
- set_mode(currcons,1);
- continue;
- case 'l':
- set_mode(currcons,0);
- continue;
- case 'n':
- if (!ques)
- if (par[0] == 5)
- status_report(tty);
- else if (par[0] == 6)
- cursor_report(currcons,tty);
- continue;
- }
- if (ques) {
- ques = 0;
- continue;
- }
- switch(c) {
- case 'G': case '`':
- if (par[0]) par[0]--;
- gotoxy(currcons,par[0],y);
- continue;
- case 'A':
- if (!par[0]) par[0]++;
- gotoxy(currcons,x,y-par[0]);
- continue;
- case 'B': case 'e':
- if (!par[0]) par[0]++;
- gotoxy(currcons,x,y+par[0]);
- continue;
- case 'C': case 'a':
- if (!par[0]) par[0]++;
- gotoxy(currcons,x+par[0],y);
- continue;
- case 'D':
- if (!par[0]) par[0]++;
- gotoxy(currcons,x-par[0],y);
- continue;
- case 'E':
- if (!par[0]) par[0]++;
- gotoxy(currcons,0,y+par[0]);
- continue;
- case 'F':
- if (!par[0]) par[0]++;
- gotoxy(currcons,0,y-par[0]);
- continue;
- case 'd':
- if (par[0]) par[0]--;
- gotoxay(currcons,x,par[0]);
- continue;
- case 'H': case 'f':
- if (par[0]) par[0]--;
- if (par[1]) par[1]--;
- gotoxay(currcons,par[1],par[0]);
- continue;
- case 'J':
- csi_J(currcons,par[0]);
- continue;
- case 'K':
- csi_K(currcons,par[0]);
- continue;
- case 'L':
- csi_L(currcons,par[0]);
- continue;
- case 'M':
- csi_M(currcons,par[0]);
- continue;
- case 'P':
- csi_P(currcons,par[0]);
- continue;
- case 'c':
- if (!par[0])
- respond_ID(tty);
- continue;
- case 'g':
- if (!par[0])
- tab_stop[x >> 5] &= ~(1 << (x & 31));
- else if (par[0] == 3) {
- tab_stop[0] =
- tab_stop[1] =
- tab_stop[2] =
- tab_stop[3] =
- tab_stop[4] = 0;
- }
- continue;
- case 'm':
- csi_m(currcons);
- continue;
- case 'q': /* DECLL - but only 3 leds */
- /* map 0,1,2,3 to 0,1,2,4 */
- if (par[0] < 4)
- setledstate(kbd_table + currcons,
- (par[0] < 3) ? par[0] : 4);
- continue;
- case 'r':
- if (!par[0])
- par[0]++;
- if (!par[1])
- par[1] = video_num_lines;
- /* Minimum allowed region is 2 lines */
- if (par[0] < par[1] &&
- par[1] <= video_num_lines) {
- top=par[0]-1;
- bottom=par[1];
- gotoxay(currcons,0,0);
- }
- continue;
- case 's':
- save_cur(currcons);
- continue;
- case 'u':
- restore_cur(currcons);
- continue;
- case 'X':
- csi_X(currcons, par[0]);
- continue;
- case '@':
- csi_at(currcons,par[0]);
- continue;
- case ']': /* setterm functions */
- setterm_command(currcons);
- continue;
- }
- continue;
- case ESpercent:
- vc_state = ESnormal;
- switch (c) {
- case '@': /* defined in ISO 2022 */
- utf = 0;
- continue;
- case 'G': /* prelim official escape code */
- case '8': /* retained for compatibility */
- utf = 1;
- continue;
- }
- continue;
- case ESfunckey:
- vc_state = ESnormal;
- continue;
- case EShash:
- vc_state = ESnormal;
- if (c == '8') {
- /* DEC screen alignment test. kludge :-) */
- video_erase_char =
- (video_erase_char & 0xff00) | 'E';
- csi_J(currcons, 2);
- video_erase_char =
- (video_erase_char & 0xff00) | ' ';
- }
- continue;
- case ESsetG0:
- if (c == '0')
- G0_charset = GRAF_MAP;
- else if (c == 'B')
- G0_charset = LAT1_MAP;
- else if (c == 'U')
- G0_charset = IBMPC_MAP;
- else if (c == 'K')
- G0_charset = USER_MAP;
- if (charset == 0)
- translate = set_translate(G0_charset);
- vc_state = ESnormal;
- continue;
- case ESsetG1:
- if (c == '0')
- G1_charset = GRAF_MAP;
- else if (c == 'B')
- G1_charset = LAT1_MAP;
- else if (c == 'U')
- G1_charset = IBMPC_MAP;
- else if (c == 'K')
- G1_charset = USER_MAP;
- if (charset == 1)
- translate = set_translate(G1_charset);
- vc_state = ESnormal;
- continue;
- default:
- vc_state = ESnormal;
- }
+ FLUSH
+ do_con_trol(tty, currcons, c);
}
+ FLUSH
enable_bh(CONSOLE_BH);
return n;
+#undef FLUSH
}
-static int con_write(struct tty_struct * tty, int from_user,
- const unsigned char *buf, int count)
-{
- int retval;
-
- retval = do_con_write(tty, from_user, buf, count);
- con_flush_chars(tty);
-
- return retval;
-}
-
-static void con_put_char(struct tty_struct *tty, unsigned char ch)
-{
- do_con_write(tty, 0, &ch, 1);
-}
-
-static int con_write_room(struct tty_struct *tty)
-{
- if (tty->stopped)
- return 0;
- return 4096; /* No limit, really; we're not buffering */
-}
-
-static int con_chars_in_buffer(struct tty_struct *tty)
-{
- return 0; /* we're not buffering */
-}
-
-void poke_blanked_console(void)
+/*
+ * This is the console switching bottom half handler.
+ *
+ * Doing console switching in a bottom half handler allows
+ * us to do the switches asynchronously (needed when we want
+ * to switch due to a keyboard interrupt), while still giving
+ * us the option to easily disable it to avoid races when we
+ * need to write to the console.
+ */
+static void console_bh(void)
{
- timer_active &= ~(1<<BLANK_TIMER);
- if (vt_cons[fg_console]->vc_mode == KD_GRAPHICS)
- return;
- if (console_blanked) {
- timer_table[BLANK_TIMER].fn = unblank_screen;
- timer_table[BLANK_TIMER].expires = 0;
- timer_active |= 1<<BLANK_TIMER;
- } else if (blankinterval) {
- timer_table[BLANK_TIMER].expires = jiffies + blankinterval;
- timer_active |= 1<<BLANK_TIMER;
+ run_task_queue(&con_task_queue);
+ if (want_console >= 0) {
+ if (want_console != fg_console && vc_cons_allocated(want_console)) {
+ hide_cursor(fg_console);
+ save_screen();
+ change_console(want_console);
+ /* we only changed when the console had already
+ been allocated - a new console is not created
+ in an interrupt routine */
+ }
+ want_console = -1;
+ }
+ if (do_poke_blanked_console) { /* do not unblank for a LED change */
+ do_poke_blanked_console = 0;
+ poke_blanked_console();
}
}
+/*
+ * Console on virtual terminal
+ */
+
#ifdef CONFIG_VT_CONSOLE
void vt_console_print(struct console *co, const char * b, unsigned count)
{
int currcons = fg_console;
unsigned char c;
static int printing = 0;
+ const ushort *start;
+ ushort cnt = 0;
+ ushort myx = x;
-#if CONFIG_AP1000
- prom_printf(b);
- return;
-#endif
if (!printable || printing)
return; /* console not yet initialized */
printing = 1;
@@ -2039,36 +1941,68 @@ void vt_console_print(struct console *co, const char * b, unsigned count)
if (!vc_cons_allocated(currcons)) {
/* impossible */
printk("vt_console_print: tty %d not allocated ??\n", currcons+1);
- return;
+ goto quit;
}
-#ifdef CONFIG_SERIAL_ECHO
- serial_echo_print(b);
-#endif /* CONFIG_SERIAL_ECHO */
+ /* undraw cursor first */
+ if (IS_FG)
+ hide_cursor(currcons);
+
+ start = (ushort *)pos;
- while (count-- > 0) {
- c = *(b++);
- if (c == 10 || c == 13 || need_wrap) {
+ /* Contrived structure to try to emulate original need_wrap behaviour
+ * Problems caused when we have need_wrap set on '\n' character */
+ disable_bh(CONSOLE_BH);
+ while (count--) {
+ enable_bh(CONSOLE_BH);
+ c = *b++;
+ disable_bh(CONSOLE_BH);
+ if (c == 10 || c == 13 || c == 8 || need_wrap) {
+ if (cnt > 0) {
+ if (IS_VISIBLE)
+ sw->con_putcs(vc_cons[currcons].d, start, cnt, y, x);
+ x += cnt;
+ if (need_wrap)
+ x--;
+ cnt = 0;
+ }
+ if (c == 8) { /* backspace */
+ bs(currcons);
+ start = (ushort *)pos;
+ myx = x;
+ continue;
+ }
if (c != 13)
lf(currcons);
cr(currcons);
+ start = (ushort *)pos;
+ myx = x;
if (c == 10 || c == 13)
continue;
}
- if (c == 8) { /* backspace */
- bs(currcons);
- continue;
- }
scr_writew((attr << 8) + c, (unsigned short *) pos);
- if (x == video_num_columns - 1) {
+ cnt++;
+ if (myx == video_num_columns - 1) {
need_wrap = 1;
continue;
}
- x++;
pos+=2;
+ myx++;
}
+ if (cnt > 0) {
+ if (IS_VISIBLE)
+ sw->con_putcs(vc_cons[currcons].d, start, cnt, y, x);
+ x += cnt;
+ if (x == video_num_columns) {
+ x--;
+ need_wrap = 1;
+ }
+ }
+ enable_bh(CONSOLE_BH);
set_cursor(currcons);
poke_blanked_console();
+
+quit:
printing = 0;
}
@@ -2077,8 +2011,6 @@ static kdev_t vt_console_device(struct console *c)
return MKDEV(TTY_MAJOR, c->index ? c->index : fg_console + 1);
}
-extern int keyboard_wait_for_keypress(struct console *);
-
struct console vt_console_driver = {
"tty",
vt_console_print,
@@ -2095,6 +2027,92 @@ struct console vt_console_driver = {
#endif
/*
+ * Handling of Linux-specific VC ioctls
+ */
+
+int tioclinux(struct tty_struct *tty, unsigned long arg)
+{
+ char type, data;
+
+ if (tty->driver.type != TTY_DRIVER_TYPE_CONSOLE)
+ return -EINVAL;
+ if (current->tty != tty && !suser())
+ return -EPERM;
+ if (get_user(type, (char *)arg))
+ return -EFAULT;
+ switch (type)
+ {
+ case 2:
+ return set_selection(arg, tty, 1);
+ case 3:
+ return paste_selection(tty);
+ case 4:
+ do_unblank_screen();
+ return 0;
+ case 5:
+ return sel_loadlut(arg);
+ case 6:
+
+ /*
+ * Make it possible to react to Shift+Mousebutton.
+ * Note that 'shift_state' is an undocumented
+ * kernel-internal variable; programs not closely
+ * related to the kernel should not use this.
+ */
+ data = shift_state;
+ return __put_user(data, (char *) arg);
+ case 7:
+ data = mouse_reporting();
+ return __put_user(data, (char *) arg);
+ case 10:
+ set_vesa_blanking(arg);
+ return 0;
+ case 11: /* set kmsg redirect */
+ if (!suser())
+ return -EPERM;
+ if (get_user(data, (char *)arg+1))
+ return -EFAULT;
+ kmsg_redirect = data;
+ return 0;
+ case 12: /* get fg_console */
+ return fg_console;
+ }
+ return -EINVAL;
+}
+
+/*
+ * /dev/ttyN handling
+ */
+
+static int con_write(struct tty_struct * tty, int from_user,
+ const unsigned char *buf, int count)
+{
+ int retval;
+
+ retval = do_con_write(tty, from_user, buf, count);
+ con_flush_chars(tty);
+
+ return retval;
+}
+
+static void con_put_char(struct tty_struct *tty, unsigned char ch)
+{
+ do_con_write(tty, 0, &ch, 1);
+}
+
+static int con_write_room(struct tty_struct *tty)
+{
+ if (tty->stopped)
+ return 0;
+ return 4096; /* No limit, really; we're not buffering */
+}
+
+static int con_chars_in_buffer(struct tty_struct *tty)
+{
+ return 0; /* we're not buffering */
+}
+
+/*
* con_throttle and con_unthrottle are only used for
* paste_selection(), which has to stuff in a large number of
* characters...
@@ -2110,9 +2128,69 @@ static void con_unthrottle(struct tty_struct *tty)
wake_up_interruptible(&vt->paste_wait);
}
-static void vc_init(unsigned int currcons, unsigned long rows, unsigned long cols, int do_clear)
+/*
+ * Turn the Scroll-Lock LED on when the tty is stopped
+ */
+static void con_stop(struct tty_struct *tty)
+{
+ int console_num;
+ if (!tty)
+ return;
+ console_num = MINOR(tty->device) - (tty->driver.minor_start);
+ if (!vc_cons_allocated(console_num))
+ return;
+ set_vc_kbd_led(kbd_table + console_num, VC_SCROLLOCK);
+ set_leds();
+}
+
+/*
+ * Turn the Scroll-Lock LED off when the console is started
+ */
+static void con_start(struct tty_struct *tty)
+{
+ int console_num;
+ if (!tty)
+ return;
+ console_num = MINOR(tty->device) - (tty->driver.minor_start);
+ if (!vc_cons_allocated(console_num))
+ return;
+ clr_vc_kbd_led(kbd_table + console_num, VC_SCROLLOCK);
+ set_leds();
+}
+
+static void con_flush_chars(struct tty_struct *tty)
+{
+ struct vt_struct *vt = (struct vt_struct *)tty->driver_data;
+
+ set_cursor(vt->vc_num);
+}
+
+/*
+ * Allocate the console screen memory.
+ */
+static int con_open(struct tty_struct *tty, struct file * filp)
+{
+ unsigned int currcons;
+ int i;
+
+ currcons = MINOR(tty->device) - tty->driver.minor_start;
+
+ i = vc_allocate(currcons, 0);
+ if (i)
+ return i;
+
+ vt_cons[currcons]->vc_num = currcons;
+ tty->driver_data = vt_cons[currcons];
+
+ if (!tty->winsize.ws_row && !tty->winsize.ws_col) {
+ tty->winsize.ws_row = video_num_lines;
+ tty->winsize.ws_col = video_num_columns;
+ }
+ return 0;
+}
+
+static void vc_init(unsigned int currcons, unsigned int rows, unsigned int cols, int do_clear)
{
- long base = (long) vc_scrbuf[currcons];
int j, k ;
video_num_columns = cols;
@@ -2120,9 +2198,8 @@ static void vc_init(unsigned int currcons, unsigned long rows, unsigned long col
video_size_row = cols<<1;
video_screen_size = video_num_lines * video_size_row;
- pos = origin = video_mem_start = base;
- scr_end = base + video_screen_size;
- video_mem_end = base + video_screen_size;
+ set_origin(currcons);
+ pos = origin;
reset_vc(currcons);
for (j=k=0; j<16; j++) {
vc_cons[currcons].d->vc_palette[k++] = default_red[j] ;
@@ -2136,83 +2213,26 @@ static void vc_init(unsigned int currcons, unsigned long rows, unsigned long col
reset_terminal(currcons, do_clear);
}
-static void con_setsize(unsigned long rows, unsigned long cols)
-{
- video_num_lines = rows;
- video_num_columns = cols;
- video_size_row = 2 * cols;
- video_screen_size = video_num_lines * video_size_row;
-}
-
/*
- * This is the console switching bottom half handler.
- *
- * Doing console switching in a bottom half handler allows
- * us to do the switches asynchronously (needed when we want
- * to switch due to a keyboard interrupt), while still giving
- * us the option to easily disable it to avoid races when we
- * need to write to the console.
- */
-static void console_bh(void)
-{
- if (want_console >= 0) {
- if (want_console != fg_console) {
- change_console(want_console);
- /* we only changed when the console had already
- been allocated - a new console is not created
- in an interrupt routine */
- }
- want_console = -1;
- }
- if (do_poke_blanked_console) { /* do not unblank for a LED change */
- do_poke_blanked_console = 0;
- poke_blanked_console();
- }
-}
-
-/*
- * unsigned long con_init(unsigned long);
- *
* This routine initializes console interrupts, and does nothing
* else. If you want the screen to clear, call tty_write with
* the appropriate escape-sequence.
- *
- * Reads the information preserved by setup.s to determine the current display
- * type and sets everything accordingly.
- *
- * FIXME: return early if we don't _have_ a video card installed.
- *
*/
-__initfunc(unsigned long con_init(unsigned long kmem_start))
-{
- const char *display_desc = "????";
- int currcons = 0;
- int orig_x = ORIG_X;
- int orig_y = ORIG_Y;
-
-#ifdef CONFIG_SGI
- if (serial_console) {
- fg_console = 0;
- rs_cons_hook(0, 0, serial_console);
- rs_cons_hook(0, 1, serial_console);
+struct tty_driver console_driver;
+static int console_refcount;
- return kmem_start;
- }
-#endif
+__initfunc(unsigned long con_init(unsigned long kmem_start))
+{
+ const char *display_desc = NULL;
+ unsigned int currcons = 0;
-#ifdef __sparc__
- if (serial_console) {
+ if (conswitchp)
+ display_desc = conswitchp->con_startup();
+ if (!display_desc) {
fg_console = 0;
-
-#if CONFIG_SUN_SERIAL
- rs_cons_hook(0, 0, serial_console);
- rs_cons_hook(0, 1, serial_console);
-#endif
-
return kmem_start;
}
-#endif
memset(&console_driver, 0, sizeof(struct tty_driver));
console_driver.magic = TTY_DRIVER_MAGIC;
@@ -2244,11 +2264,6 @@ __initfunc(unsigned long con_init(unsigned long kmem_start))
if (tty_register_driver(&console_driver))
panic("Couldn't register console driver\n");
-#if CONFIG_AP1000
- return(kmem_start);
-#endif
- con_setsize(ORIG_VIDEO_LINES, ORIG_VIDEO_COLS);
-
timer_table[BLANK_TIMER].fn = blank_screen;
timer_table[BLANK_TIMER].expires = 0;
if (blankinterval) {
@@ -2256,16 +2271,7 @@ __initfunc(unsigned long con_init(unsigned long kmem_start))
timer_active |= 1<<BLANK_TIMER;
}
- kmem_start = con_type_init(kmem_start, &display_desc);
-
- hardscroll_enabled = (hardscroll_disabled_by_init ? 0 :
- (video_type == VIDEO_TYPE_EGAC
- || video_type == VIDEO_TYPE_VGAC
- || video_type == VIDEO_TYPE_EGAM
- || video_type == VIDEO_TYPE_PICA_S3
- || video_type == VIDEO_TYPE_SNI_RM ));
- has_wrapped = 0 ;
-
+ /* Unfortunately, kmalloc is not running yet */
/* Due to kmalloc roundup allocating statically is more efficient -
so provide MIN_NR_CONSOLES for people with very little memory */
for (currcons = 0; currcons < MIN_NR_CONSOLES; currcons++) {
@@ -2275,11 +2281,12 @@ __initfunc(unsigned long con_init(unsigned long kmem_start))
kmem_start += sizeof(struct vc_data);
vt_cons[currcons] = (struct vt_struct *) kmem_start;
kmem_start += sizeof(struct vt_struct);
- vc_scrbuf[currcons] = (unsigned short *) kmem_start;
+ visual_init(currcons);
+ screenbuf = (unsigned short *) kmem_start;
kmem_start += video_screen_size;
kmalloced = 0;
- screenbuf_size = video_screen_size;
- vc_init(currcons, video_num_lines, video_num_columns, currcons);
+ vc_init(currcons, video_num_lines, video_num_columns,
+ currcons || !sw->con_save_screen);
for (j=k=0; j<16; j++) {
vc_cons[currcons].d->vc_palette[k++] = default_red[j] ;
vc_cons[currcons].d->vc_palette[k++] = default_grn[j] ;
@@ -2288,77 +2295,100 @@ __initfunc(unsigned long con_init(unsigned long kmem_start))
}
currcons = fg_console = 0;
-
- video_mem_start = video_mem_base;
- video_mem_end = video_mem_term;
- origin = video_mem_start;
- scr_end = video_mem_start + video_num_lines * video_size_row;
- gotoxy(currcons,orig_x,orig_y);
+ master_display_fg = vc_cons[currcons].d;
set_origin(currcons);
+ save_screen();
+ gotoxy(currcons,x,y);
csi_J(currcons, 0);
+ update_screen(fg_console);
+ set_cursor(currcons);
+ printk("Console: %s %s %dx%d",
+ can_do_color ? "colour" : "mono",
+ display_desc, video_num_columns, video_num_lines);
+ printable = 1;
+ printk("\n");
- /* Figure out the size of the screen and screen font so we
- can figure out the appropriate screen size should we load
- a different font */
+#ifdef CONFIG_VT_CONSOLE
+ register_console(&vt_console_driver);
+#endif
- printable = 1;
- if ( video_type == VIDEO_TYPE_VGAC || video_type == VIDEO_TYPE_EGAC
- || video_type == VIDEO_TYPE_EGAM || video_type == VIDEO_TYPE_TGAC
- || video_type == VIDEO_TYPE_SGI || video_type == VIDEO_TYPE_SUN )
- {
- default_font_height = video_font_height = ORIG_VIDEO_POINTS;
- /* This may be suboptimal but is a safe bet - go with it */
- video_scan_lines = video_font_height * video_num_lines;
+ init_bh(CONSOLE_BH, console_bh);
+
+ return kmem_start;
+}
-#ifdef CONFIG_SERIAL_ECHO
- serial_echo_init(SERIAL_ECHO_PORT);
-#endif /* CONFIG_SERIAL_ECHO */
+/*
+ * If we support more console drivers, this function is used
+ * when a driver wants to take over some existing consoles
+ * and become default driver for newly opened ones.
+ */
- printk("Console: %ld point font, %ld scans\n",
- video_font_height, video_scan_lines);
- }
-#if defined(CONFIG_ACER_PICA_61) || defined(CONFIG_SNI_RM200_PCI)
- else if (video_type == VIDEO_TYPE_PICA_S3 ||
- video_type == VIDEO_TYPE_SNI_RM)
- {
- /*
- * Fixme: we should detect this. But still 16 is a reasonable
- * assumption.
- */
- default_font_height = video_font_height = 16;
- /* This may be suboptimal but is a safe bet - go with it */
- video_scan_lines = video_font_height * video_num_lines;
-
-#ifdef CONFIG_SERIAL_ECHO
- serial_echo_init(SERIAL_ECHO_PORT);
-#endif /* CONFIG_SERIAL_ECHO */
-
- printk("Console: %ld point font, %ld scans\n",
- video_font_height, video_scan_lines);
- }
-#endif
+#ifndef VT_BUF_VRAM_ONLY
- printk("Console: %s %s %ldx%ld, %d virtual console%s (max %d)\n",
- can_do_color ? "colour" : "mono",
- display_desc, video_num_columns, video_num_lines,
- MIN_NR_CONSOLES, (MIN_NR_CONSOLES == 1) ? "" : "s",
- MAX_NR_CONSOLES);
+void take_over_console(struct consw *csw, int first, int last, int deflt)
+{
+ int i;
+ const char *desc;
- con_type_init_finish();
+ if (deflt)
+ conswitchp = csw;
+ desc = csw->con_startup();
+ if (!desc) return;
+
+ for (i = first; i <= last; i++) {
+ if (!vc_cons[i].d || !vc_cons[i].d->vc_sw)
+ continue;
+ if (i == fg_console &&
+ vc_cons[i].d->vc_sw->con_save_screen)
+ vc_cons[i].d->vc_sw->con_save_screen(vc_cons[i].d);
+ vc_cons[i].d->vc_sw->con_deinit(vc_cons[i].d);
+ vc_cons[i].d->vc_sw = csw;
+ vc_cons[i].d->vc_sw->con_init(vc_cons[i].d, 0);
+ }
+ printk("Console: switching to %s %s %dx%d\n",
+ vc_cons[fg_console].d->vc_can_do_color ? "colour" : "mono",
+ desc, vc_cons[fg_console].d->vc_cols, vc_cons[fg_console].d->vc_rows);
+ set_palette();
+}
- /*
- * can't register TGA yet, because PCI bus probe has *not* taken
- * place before con_init() gets called. Trigger the real TGA hw
- * initialization and register_console() event from
- * within the bus probing code... :-(
- */
-#ifdef CONFIG_VT_CONSOLE
- if (video_type != VIDEO_TYPE_TGAC && con_is_present())
- register_console(&vt_console_driver);
#endif
- init_bh(CONSOLE_BH, console_bh);
- return kmem_start;
+/*
+ * Screen blanking
+ */
+
+void set_vesa_blanking(unsigned long arg)
+{
+ char *argp = (char *)arg + 1;
+ unsigned int mode;
+ get_user(mode, argp);
+ vesa_blank_mode = (mode < 4) ? mode : 0;
+}
+
+void vesa_blank(void)
+{
+ struct vc_data *c = vc_cons[fg_console].d;
+ c->vc_sw->con_blank(c, vesa_blank_mode + 1);
+}
+
+void vesa_powerdown(void)
+{
+ struct vc_data *c = vc_cons[fg_console].d;
+ /*
+ * Power down if currently suspended (1 or 2),
+ * suspend if currently blanked (0),
+ * else do nothing (i.e. already powered down (3)).
+ * Called only if powerdown features are allowed.
+ */
+ switch (vesa_blank_mode) {
+ case VESA_NO_BLANKING:
+ c->vc_sw->con_blank(c, VESA_VSYNC_SUSPEND+1);
+ break;
+ case VESA_VSYNC_SUSPEND:
+ case VESA_HSYNC_SUSPEND:
+ c->vc_sw->con_blank(c, VESA_POWERDOWN+1);
+ break;
+ }
}
void vesa_powerdown_screen(void)
@@ -2371,11 +2401,29 @@ void vesa_powerdown_screen(void)
void do_blank_screen(int nopowersave)
{
- int currcons;
+ int currcons = fg_console;
+ int i;
if (console_blanked)
return;
+ /* entering graphics mode? */
+ if (nopowersave) {
+ hide_cursor(currcons);
+ save_screen();
+ sw->con_blank(vc_cons[currcons].d, -1);
+ console_blanked = fg_console + 1;
+ set_origin(currcons);
+ return;
+ }
+
+ /* don't blank graphics */
+ if (vt_cons[fg_console]->vc_mode != KD_TEXT) {
+ console_blanked = fg_console + 1;
+ return;
+ }
+
+ hide_cursor(fg_console);
if(vesa_off_interval && !nopowersave) {
timer_table[BLANK_TIMER].fn = vesa_powerdown_screen;
timer_table[BLANK_TIMER].expires = jiffies + vesa_off_interval;
@@ -2385,18 +2433,12 @@ void do_blank_screen(int nopowersave)
timer_table[BLANK_TIMER].fn = unblank_screen;
}
- /* try not to lose information by blanking, and not to waste memory */
- currcons = fg_console;
- has_scrolled = 0;
- blank__origin = __origin;
- blank_origin = origin;
- set_origin(fg_console);
- get_scrmem(fg_console);
- unblank_origin = origin;
- memsetw((void *)blank_origin, BLANK,
- 2*video_num_lines*video_num_columns);
- hide_cursor();
+ save_screen();
+ /* In case we need to reset origin, blanking hook returns 1 */
+ i = sw->con_blank(vc_cons[currcons].d, 1);
console_blanked = fg_console + 1;
+ if (i)
+ set_origin(currcons);
if(!nopowersave)
{
@@ -2411,9 +2453,6 @@ void do_blank_screen(int nopowersave)
void do_unblank_screen(void)
{
int currcons;
- int resetorg;
- long offset;
-
if (!console_blanked)
return;
if (!vc_cons_allocated(fg_console)) {
@@ -2428,34 +2467,16 @@ void do_unblank_screen(void)
}
currcons = fg_console;
- offset = 0;
- resetorg = 0;
- if (console_blanked == fg_console + 1 && origin == unblank_origin
- && !has_scrolled) {
- /* try to restore the exact situation before blanking */
- resetorg = 1;
- offset = (blank_origin - video_mem_base)
- - (unblank_origin - video_mem_start);
- }
-
console_blanked = 0;
- set_scrmem(fg_console, offset);
- set_origin(fg_console);
- set_cursor(fg_console);
- if (resetorg)
- __set_origin(blank__origin);
-
- vesa_unblank();
#ifdef CONFIG_APM
- if (apm_display_unblank())
- return;
+ apm_display_unblank();
#endif
+ if (sw->con_blank(vc_cons[currcons].d, 0))
+ /* Low-level driver cannot restore -> do it ourselves */
+ update_screen(fg_console);
+ set_cursor(fg_console);
}
-/*
- * If a blank_screen is due to a timer, then a power save is allowed.
- * If it is related to console_switching, then avoid vesa_blank().
- */
static void blank_screen(void)
{
do_blank_screen(0);
@@ -2466,62 +2487,60 @@ static void unblank_screen(void)
do_unblank_screen();
}
-void update_screen(int new_console)
+void poke_blanked_console(void)
{
- static int lock = 0;
-
- if (new_console == fg_console || lock)
- return;
- if (!vc_cons_allocated(new_console)) {
- /* strange ... */
- printk("update_screen: tty %d not allocated ??\n", new_console+1);
+ timer_active &= ~(1<<BLANK_TIMER);
+ if (vt_cons[fg_console]->vc_mode == KD_GRAPHICS)
return;
+ if (console_blanked) {
+ timer_table[BLANK_TIMER].fn = unblank_screen;
+ timer_table[BLANK_TIMER].expires = 0;
+ timer_active |= 1<<BLANK_TIMER;
+ } else if (blankinterval) {
+ timer_table[BLANK_TIMER].expires = jiffies + blankinterval;
+ timer_active |= 1<<BLANK_TIMER;
}
- lock = 1;
-
- clear_selection();
-
- if (!console_blanked)
- get_scrmem(fg_console);
- else
- console_blanked = -1; /* no longer of the form console+1 */
- fg_console = new_console; /* this is the only (nonzero) assignment to fg_console */
- /* consequently, fg_console will always be allocated */
- set_scrmem(fg_console, 0);
- set_origin(fg_console);
- set_cursor(fg_console);
- set_leds();
- compute_shiftstate();
- lock = 0;
}
/*
- * Allocate the console screen memory.
+ * Palettes
*/
-static int con_open(struct tty_struct *tty, struct file * filp)
-{
- unsigned int idx;
- int i;
-
- idx = MINOR(tty->device) - tty->driver.minor_start;
- i = vc_allocate(idx);
- if (i)
- return i;
+void set_palette(void)
+{
+ if (vt_cons[fg_console]->vc_mode != KD_GRAPHICS)
+ vc_cons[fg_console].d->vc_sw->con_set_palette(vc_cons[fg_console].d, color_table);
+}
- vt_cons[idx]->vc_num = idx;
- tty->driver_data = vt_cons[idx];
+int set_get_cmap(unsigned char *arg, int set)
+{
+ int i, j, k;
- if (!tty->winsize.ws_row && !tty->winsize.ws_col) {
- tty->winsize.ws_row = video_num_lines;
- tty->winsize.ws_col = video_num_columns;
+ for (i = 0; i < 16; i++)
+ if (set) {
+ get_user(default_red[i], arg++);
+ get_user(default_grn[i], arg++);
+ get_user(default_blu[i], arg++);
+ } else {
+ put_user(default_red[i], arg++);
+ put_user(default_grn[i], arg++);
+ put_user(default_blu[i], arg++);
}
- return 0;
+ if (set) {
+ for (i = 0; i < MAX_NR_CONSOLES; i++)
+ if (vc_cons_allocated(i))
+ for (j = k = 0; j < 16; j++) {
+ vc_cons[i].d->vc_palette[k++] = default_red[j];
+ vc_cons[i].d->vc_palette[k++] = default_grn[j];
+ vc_cons[i].d->vc_palette[k++] = default_blu[j];
+ }
+ set_palette();
+ }
+ return 0;
}
-
/*
- * Load palette into the EGA/VGA DAC registers. arg points to a colour
+ * Load palette into the DAC registers. arg points to a colour
* map, 3 bytes per colour, 16 colours, range from 0 to 255.
*/
@@ -2547,25 +2566,164 @@ void reset_palette (int currcons)
}
/*
- * Load font into the EGA/VGA character generator. arg points to a 8192
- * byte map, 32 bytes per character. Only first H of them are used for
- * 8xH fonts (0 < H <= 32).
+ * Font switching
+ *
+ * Currently we only support fonts up to 32 pixels wide, at a maximum height
+ * of 32 pixels. Userspace fontdata is stored with 32 bytes (shorts/ints,
+ * depending on width) reserved for each character which is kinda wasty, but
+ * this is done in order to maintain compatibility with the EGA/VGA fonts. It
+ * is upto the actual low-level console-driver convert data into its favorite
+ * format (maybe we should add a `fontoffset' field to the `display'
+ * structure so we wont have to convert the fontdata all the time.
+ * /Jes
+ */
+
+#define max_font_size 65536
+
+int con_font_op(int currcons, struct console_font_op *op)
+{
+ int rc = -EINVAL;
+ int size = max_font_size, set;
+ u8 *temp = NULL;
+ struct console_font_op old_op;
+
+ if (vt_cons[currcons]->vc_mode != KD_TEXT)
+ goto quit;
+ memcpy(&old_op, op, sizeof(old_op));
+ if (op->op == KD_FONT_OP_SET) {
+ if (!op->data)
+ return -EINVAL;
+ if (op->charcount > 512)
+ goto quit;
+ if (!op->height) { /* Need to guess font height [compat] */
+ int h, i;
+ u8 *charmap = op->data, tmp;
+
+ /* If from KDFONTOP ioctl, don't allow things which can be done in userland,
+ so that we can get rid of this soon */
+ if (!(op->flags & KD_FONT_FLAG_OLD))
+ goto quit;
+ rc = -EFAULT;
+ for (h = 32; h > 0; h--)
+ for (i = 0; i < op->charcount; i++) {
+ if (get_user(tmp, &charmap[32*i+h-1]))
+ goto quit;
+ if (tmp)
+ goto nonzero;
+ }
+ rc = -EINVAL;
+ goto quit;
+ nonzero:
+ rc = -EINVAL;
+ op->height = h;
+ }
+ if (op->width > 32 || op->height > 32)
+ goto quit;
+ size = (op->width+7)/8 * 32 * op->charcount;
+ if (size > max_font_size)
+ return -ENOSPC;
+ set = 1;
+ } else if (op->op == KD_FONT_OP_GET)
+ set = 0;
+ else
+ return sw->con_font_op(vc_cons[currcons].d, op);
+ if (op->data) {
+ temp = kmalloc(size, GFP_KERNEL);
+ if (!temp)
+ return -ENOMEM;
+ if (set && copy_from_user(temp, op->data, size)) {
+ rc = -EFAULT;
+ goto quit;
+ }
+ op->data = temp;
+ }
+ rc = sw->con_font_op(vc_cons[currcons].d, op);
+ op->data = old_op.data;
+ if (!rc && !set) {
+ int c = (op->width+7)/8 * 32 * op->charcount;
+
+ if (op->data && op->charcount > old_op.charcount)
+ rc = -ENOSPC;
+ if (!(op->flags & KD_FONT_FLAG_OLD)) {
+ if (op->width > old_op.width ||
+ op->height > old_op.height)
+ rc = -ENOSPC;
+ } else {
+ if (op->width != 8)
+ rc = -EIO;
+ else if ((old_op.height && op->height > old_op.height) ||
+ op->height > 32)
+ rc = -ENOSPC;
+ }
+ if (!rc && op->data && copy_to_user(op->data, temp, c))
+ rc = -EFAULT;
+ }
+quit: if (temp)
+ kfree_s(temp, size);
+ return rc;
+}
+
+/*
+ * Interface exported to selection and vcs.
*/
-int con_set_font (char *arg, int ch512)
+/* used by selection */
+u16 screen_glyph(int currcons, int offset)
{
- int i;
+ u16 w = scr_readw(screenpos(currcons, offset, 1));
+ u16 c = w & 0xff;
- i = set_get_font (arg,1,ch512);
- if ( !i ) {
- hashtable_contents_valid = 0;
- video_mode_512ch = ch512;
- console_charmask = ch512 ? 0x1ff : 0x0ff;
- }
- return i;
+ if (w & hi_font_mask)
+ c |= 0x100;
+ return c;
+}
+
+/* used by vcs - note the word offset */
+unsigned short *screen_pos(int currcons, int w_offset, int viewed)
+{
+ return screenpos(currcons, 2 * w_offset, viewed);
+}
+
+void getconsxy(int currcons, char *p)
+{
+ p[0] = x;
+ p[1] = y;
}
-int con_get_font (char *arg)
+void putconsxy(int currcons, char *p)
{
- return set_get_font (arg,0,video_mode_512ch);
+ gotoxy(currcons, p[0], p[1]);
+ set_cursor(currcons);
}
+
+u16 vcs_scr_readw(int currcons, u16 *org)
+{
+ if ((unsigned long)org == pos && softcursor_original != -1)
+ return softcursor_original;
+ return scr_readw(org);
+}
+
+void vcs_scr_writew(int currcons, u16 val, u16 *org)
+{
+ scr_writew(val, org);
+ if ((unsigned long)org == pos) {
+ softcursor_original = -1;
+ add_softcursor(currcons);
+ }
+}
+
+
+/*
+ * Visible symbols for modules
+ */
+
+EXPORT_SYMBOL(color_table);
+EXPORT_SYMBOL(default_red);
+EXPORT_SYMBOL(default_grn);
+EXPORT_SYMBOL(default_blu);
+EXPORT_SYMBOL(video_font_height);
+EXPORT_SYMBOL(video_scan_lines);
+
+#ifndef VT_BUF_VRAM_ONLY
+EXPORT_SYMBOL(take_over_console);
+#endif