patch-2.1.109 linux/drivers/char/console.c
Next file: linux/drivers/char/console_macros.h
Previous file: linux/drivers/char/Makefile
Back to the patch index
Back to the overall index
- Lines: 3195
- Date:
Fri Jul 10 15:31:12 1998
- Orig file:
v2.1.108/linux/drivers/char/console.c
- Orig date:
Wed Jun 24 22:54:04 1998
diff -u --recursive --new-file v2.1.108/linux/drivers/char/console.c linux/drivers/char/console.c
@@ -3,39 +3,8 @@
*
* Copyright (C) 1991, 1992 Linus Torvalds
*/
+
/*
- * console.c
- *
- * This module exports the console io functions:
- *
- * 'int vc_allocate(unsigned int console)'
- * 'int vc_cons_allocated(unsigned int console)'
- * 'int vc_resize(unsigned long lines, unsigned long cols)'
- * 'int vc_resize_con(unsigned long lines, unsigned long cols,
- * unsigned int currcons)'
- * '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(struct console *co, const char * b,
- * unsigned count)'
- * '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.
@@ -87,36 +56,20 @@
* registers (e.g. a TMS340x0 GSP).
*
* The interface to the hardware is specified using a special structure
- * (struct consw) which contains function pointers to the following
- * operations:
- *
- * unsigned long con_startup(unsigned long kmem_start,
- * const char **display_desc)
- * void con_init(struct vc_data *conp)
- * int con_deinit(struct vc_data *conp)
- * int con_clear(struct vc_data *conp, int sy, int sx, int height,
- * int width)
- * int con_putc(struct vc_data *conp, int c, int y, int x)
- * int con_putcs(struct vc_data *conp, const char *s, int count, int y,
- * int x)
- * int con_cursor(struct vc_data *conp, int mode)
- * int con_scroll(struct vc_data *conp, int t, int b, int dir, int count)
- * int con_bmove(struct vc_data *conp, int sy, int sx, int dy, int dx,
- * int height, int width)
- * int con_switch(struct vc_data *conp)
- * int con_blank(int blank)
- * int con_get_font(struct vc_data *conp, int *w, int *h, char *data)
- * int con_set_font(struct vc_data *conp, int w, int h, char *data)
- * int con_set_palette(struct vc_data *conp, unsigned char *table)
- * int con_scrolldelta(struct vc_data *conp, int lines)
+ * (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
*/
+#include <linux/module.h>
#include <linux/sched.h>
#include <linux/tty.h>
#include <linux/tty_flip.h>
@@ -133,6 +86,7 @@
#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>
@@ -145,11 +99,7 @@
#include <asm/io.h>
#include <asm/system.h>
#include <asm/uaccess.h>
-#include <asm/bitops.h>
-#ifndef CONFIG_ABSCON_COMPAT
-#define INCLUDE_LINUX_LOGO_DATA
-#endif
#include <asm/linux_logo.h>
#include "console_macros.h"
@@ -157,48 +107,8 @@
struct consw *conswitchp = NULL;
-int (*console_show_logo)(void) __initdata = NULL;
-
static int vesa_blank_mode = 0; /* 0:none 1:suspendV 2:suspendH 3:powerdown */
-static inline void hide_cursor(int currcons)
-{
- sw->con_cursor(vc_cons[currcons].d,CM_ERASE);
-}
-
-void set_cursor(int currcons)
-{
- if (currcons != fg_console || console_blanked || vcmode == KD_GRAPHICS)
- return;
- if (deccm)
- sw->con_cursor(vc_cons[currcons].d,CM_DRAW);
- else
- hide_cursor(currcons);
-}
-
- /*
- * Adjust the screen to fit a font of a certain height
- *
- * Returns < 0 for error, 0 if nothing changed, and the number
- * of lines on the adjusted console if changed.
- */
-
-int con_adjust_height(unsigned long fontheight)
-{
- int currcons = fg_console;
- /* ++Geert: Always assume that the number of lines did change? */
- return video_num_lines;
-}
-
-/* dummy functions */
-
-void no_scroll(char *str, int *ints)
-{
-}
-
-
-#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
@@ -213,60 +123,36 @@
#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.
- */
-
#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 vc_init(unsigned int console, unsigned long rows,
- unsigned long cols, int do_clear);
+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 update_attr(int currcons);
static void gotoxy(int currcons, int new_x, int new_y);
static void save_cur(int currcons);
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_powerdown(void);
-extern void compute_shiftstate(void);
-extern void reset_palette(int currcons);
-extern void set_palette(void);
+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 short console_charmask = 0x0ff;
-/* used by kbd_bh - set by keyboard_interrupt */
- int do_poke_blanked_console = 0;
- int console_blanked = 0;
+int do_poke_blanked_console = 0;
+int console_blanked = 0;
+
static int blankinterval = 10*60*HZ;
static int vesa_off_interval = 0;
-static char putcs_buf[256];
-
/*
* fg_console is the current virtual console,
* last_console is the last used one,
@@ -278,6 +164,336 @@
int want_console = -1;
int kmsg_redirect = 0;
+/*
+ * Low-Level Functions
+ */
+
+#define IS_FG (currcons == fg_console)
+
+#ifdef VT_BUF_VRAM_ONLY
+#define DO_UPDATE 0
+#else
+#define DO_UPDATE IS_FG
+#endif
+
+static inline unsigned short *screenpos(int currcons, int offset, int viewed)
+{
+ unsigned short *p = (unsigned short *)(visible_origin + offset);
+ return p;
+}
+
+/* FIXME: Can we do the whole scrollback logic here and call the driver
+ * only for changing the display? Yes, there is some magic with
+ * blanked screens, but we could unblank here. (Argh, there might
+ * be some problems with unblanking since this is called from real
+ * interrupts...) --mj
+ */
+static inline void scrolldelta(int lines)
+{
+ int currcons = fg_console;
+
+ 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_FG && 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 count;
+ unsigned int step;
+
+ if (t+nr >= b)
+ nr = b - t - 1;
+ if (b > video_num_lines || t >= b || nr < 1)
+ return;
+ if (IS_FG && sw->con_scroll(vc_cons[currcons].d, t, b, SM_DOWN, nr))
+ return;
+ s = (unsigned short *) (origin+video_size_row*(b-nr-1));
+ step = video_num_columns * nr;
+ count = b - t - nr;
+ while (count--) {
+ scr_memcpyw(s + step, s, video_size_row);
+ s -= video_num_columns;
+ }
+ count = nr;
+ while (count--) {
+ s += video_num_columns;
+ scr_memsetw(s, video_erase_char, video_size_row);
+ }
+}
+
+static void update_attr(int currcons)
+{
+/*
+ * ++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
+ *
+ * ++Geert: TODO: Because the attributes have different meanings
+ * for monochrome and color, they should really be converted if
+ * can_do_color changes...
+ *
+ * FIXME: Monochrome attributes on MDA/HGC/etc
+ */
+ if (!can_do_color) {
+ /* Special treatment for monochrome */
+ attr = intensity |
+ (underline ? 4 : 0) |
+ ((reverse ^ decscnm) ? 8 : 0) |
+ (blink ? 0x80 : 0);
+ video_erase_char = ' ' | ((reverse ^ decscnm) ? 0x800 : 0);
+ return;
+ }
+ 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 (decscnm)
+ video_erase_char = (reverse_video_char(color) << 8) | ' ';
+ else
+ video_erase_char = (color << 8) | ' ';
+}
+
+/* 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;
+ int xx = (offset >> 1) % video_num_columns;
+ int yy = (offset >> 1) / video_num_columns;
+
+ count /= 2;
+ p = screenpos(currcons, offset, viewed);
+ if (can_do_color)
+ while (count--) {
+ unsigned short old = scr_readw(p);
+ unsigned short new = reverse_video_short(old);
+ scr_writew(new, p);
+ p++;
+ if (DO_UPDATE) {
+ sw->con_putc(vc_cons[currcons].d, new, yy, xx);
+ if (++xx == video_num_columns)
+ xx = 0, ++yy;
+ }
+ }
+ else
+ while (count--) {
+ unsigned short old = scr_readw(p);
+ unsigned short new = reverse_video_short_mono(old);
+ scr_writew(new, p);
+ p++;
+ if (DO_UPDATE) {
+ sw->con_putc(vc_cons[currcons].d, new, yy, xx);
+ if (++xx == video_num_columns)
+ xx = 0, ++yy;
+ }
+ }
+}
+
+/* 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 (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);
+ oldx = (offset >> 1) % video_num_columns;
+ oldy = (offset >> 1) / video_num_columns;
+ new = complement_video_short(old);
+ scr_writew(new, p);
+ if (DO_UPDATE)
+ sw->con_putc(vc_cons[currcons].d, new, oldy, oldx);
+ }
+}
+
+/* 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;
+}
+
+static void insert_char(int currcons, unsigned int nr)
+{
+ unsigned short *p, *q = (unsigned short *) pos;
+
+ 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;
+ }
+}
+
+/* FIXME: Does it make sense to hide cursor on non-fg consoles? */
+static inline void hide_cursor(int currcons)
+{
+ sw->con_cursor(vc_cons[currcons].d,CM_ERASE);
+}
+
+void set_cursor(int currcons)
+{
+ if (!IS_FG || console_blanked || vcmode == KD_GRAPHICS)
+ return;
+ if (deccm)
+ sw->con_cursor(vc_cons[currcons].d,CM_DRAW);
+ else
+ hide_cursor(currcons);
+}
+
+static void set_origin(int currcons)
+{
+ if (!IS_FG ||
+ !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 xx, yy, startx, attrib;
+ unsigned short *p, *q;
+ static int lock = 0;
+
+ if (lock)
+ return;
+ if (!vc_cons_allocated(new_console)) {
+ /* strange ... */
+ printk("update_screen: tty %d not allocated ??\n", new_console+1);
+ return;
+ }
+ lock = 1;
+
+ clear_selection();
+
+ fg_console = new_console;
+ set_origin(currcons);
+ currcons = new_console;
+ sw->con_cursor (vc_cons[currcons].d, CM_ERASE);
+ set_origin(currcons);
+ if (sw->con_switch (vc_cons[currcons].d)) {
+ /* Update the screen contents */
+ p = (unsigned short *)origin;
+ attrib = scr_readw(p) & 0xff00;
+ for (yy = 0; yy < video_num_lines; yy++) {
+ q = p;
+ for (startx = xx = 0; xx < video_num_columns; xx++) {
+ 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++;
+ }
+ if (p > q)
+ sw->con_putcs (vc_cons[currcons].d, q,
+ p - q, yy, startx);
+ }
+ }
+ set_cursor (currcons);
+ set_leds();
+ compute_shiftstate();
+ lock = 0;
+}
+
+/*
+ * Allocation, freeing and resizing of VTs.
+ */
+
int vc_cons_allocated(unsigned int i)
{
return (i < MAX_NR_CONSOLES && vc_cons[i].d);
@@ -288,12 +504,12 @@
/* ++Geert: sw->con_init determines console size */
sw = conswitchp;
cons_num = currcons;
- sw->con_init(vc_cons[currcons].d);
+ sw->con_init(vc_cons[currcons].d, 1);
video_size_row = video_num_columns<<1;
video_screen_size = video_num_lines*video_size_row;
}
-int vc_allocate(unsigned int currcons) /* return 0 on success */
+int vc_allocate(unsigned int currcons, int init) /* return 0 on success */
{
if (currcons >= MAX_NR_CONSOLES)
return -ENXIO;
@@ -307,6 +523,9 @@
/* 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) */
+ /* 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)
return -ENOMEM;
@@ -320,10 +539,13 @@
vt_cons[currcons] = NULL;
return -ENOMEM;
}
- vc_scrbuf[currcons] = (unsigned short *) q;
- vc_cons[currcons].d->vc_kmalloced = 1;
- vc_cons[currcons].d->vc_screenbuf_size = video_screen_size;
- vc_init(currcons, video_num_lines, video_num_columns, 1);
+ 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;
}
@@ -333,187 +555,105 @@
* [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)
+/* FIXME: Cursor sometimes disappears when resizing */
+/* FIXME: We could also take data from the scrollback buffer */
+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 = 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;
-
- /*
- * 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;
- }
- newscreens[currcons] = p;
- }
- }
-
- for (currcons = 0; currcons < MAX_NR_CONSOLES; currcons++) {
- if (!vc_cons_allocated(currcons))
- continue;
-
- 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];
- if (ll < oll)
- ol += (oll - ll) * osr;
-
- update_attr(currcons);
- 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], oss);
- vc_scrbuf[currcons] = newscreens[currcons];
- kmalloced = 1;
- screenbuf_size = ss;
-
- origin = video_mem_start = (long) vc_scrbuf[currcons];
- scr_end = video_mem_end = video_mem_start + ss;
-
- 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);
- }
-
- /* don't update in graphics mode */
- if (currcons == fg_console && vt_cons[fg_console]->vc_mode == KD_TEXT)
- update_screen(fg_console);
-
- set_cursor(fg_console);
-
- return 0;
-}
-
-/*
- * ++Geert: Change # of rows and columns for one specific console.
- * Of course it's not messy to have all consoles of potentially different
- * sizes, except on PCish hardware :-)
- */
-void vc_resize_con(unsigned long lines, unsigned long cols,
- unsigned int currcons)
-{
- unsigned long cc, ll, ss, sr;
- unsigned long occ, oll, oss, osr;
- unsigned short *newscreen;
- long ol, nl, rlth, rrem;
-
- if (!cols || !lines || currcons >= MAX_NR_CONSOLES)
- return;
+ unsigned int cc, ll, ss, sr, todo = 0;
+ unsigned int occ, oll, oss, osr;
+ unsigned short *p;
+ unsigned int currcons = fg_console, i;
+ unsigned short *newscreens[MAX_NR_CONSOLES];
+ unsigned long ol, nl, rlth, rrem;
- cc = cols;
- ll = lines;
+ cc = (cols ? cols : video_num_columns);
+ ll = (lines ? lines : video_num_lines);
sr = cc << 1;
ss = sr * ll;
- if (!vc_cons_allocated(currcons))
- newscreen = 0;
- else if (!(newscreen = (unsigned short *)kmalloc(ss, GFP_USER)))
- return;
-
- if (vc_cons_allocated(currcons)) {
- 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) newscreen;
- if (ll < oll)
- ol += (oll - ll) * osr;
-
- /* ++Geert: TODO: Because the attributes have different meanings
- for monochrome and color, they should really be converted if
- can_do_color changes... */
- update_attr(currcons);
- 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;
- }
+ for (currcons = first; currcons <= last; currcons++) {
+ if (!vc_cons_allocated(currcons) ||
+ (cc == video_num_columns && ll == video_num_lines))
+ newscreens[currcons] = NULL;
+ 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;
+ }
+ newscreens[currcons] = p;
+ todo++;
+ }
+ }
+ if (!todo)
+ return 0;
- if (kmalloced)
- kfree_s(vc_scrbuf[currcons], oss);
- vc_scrbuf[currcons] = newscreen;
- kmalloced = 1;
- screenbuf_size = ss;
+ for (currcons = first; currcons <= last; currcons++) {
+ 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];
+ 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 (scr_end > nl)
- memsetw((void *) nl, video_erase_char, scr_end - nl);
+ if (kmalloced)
+ kfree_s(screenbuf, oss);
+ screenbuf = newscreens[currcons];
+ kmalloced = 1;
+ screenbuf_size = ss;
+ set_origin(currcons);
+
+ if (scr_end > nl)
+ scr_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 (console_table[currcons]) {
- struct winsize ws, *cws = &console_table[currcons]->winsize;
- 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;
- }
+ if (IS_FG && vt_cons[fg_console]->vc_mode == KD_TEXT)
+ update_screen(fg_console);
}
- /* don't update in graphics mode */
- if (currcons == fg_console && vt_cons[fg_console]->vc_mode == KD_TEXT)
- update_screen(fg_console);
+ set_cursor(fg_console);
+ return 0;
}
@@ -522,13 +662,16 @@
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)
@@ -551,7 +694,7 @@
/* the default colour table, for VGA+ colour systems */
int default_red[] = {0x00,0xaa,0x00,0xaa,0x00,0xaa,0x00,0xaa,
0x55,0xff,0x55,0xff,0x55,0xff,0x55,0xff};
-int default_grn[] = {0x00,0x00,0xaa,0xaa,0x00,0x00,0xaa,0xaa,
+int default_grn[] = {0x00,0x00,0xaa,0x55,0x00,0x00,0xaa,0xaa,
0x55,0x55,0xff,0xff,0x55,0x55,0xff,0xff};
int default_blu[] = {0x00,0x00,0x00,0x00,0xaa,0xaa,0xaa,0xaa,
0x55,0x55,0x55,0x55,0xff,0xff,0xff,0xff};
@@ -595,15 +738,6 @@
gotoxy(currcons, new_x, decom ? (top+new_y) : new_y);
}
-/*
- * Hardware scrollback support
- */
-static inline void scrolldelta(int lines)
-{
- int currcons = fg_console;
- sw->con_scrolldelta(vc_cons[currcons].d, lines);
-}
-
void scrollback(int lines)
{
int currcons = fg_console;
@@ -622,50 +756,6 @@
scrolldelta(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;
- d = (unsigned short *) (origin+video_size_row*t);
- 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);
- if (currcons == fg_console)
- sw->con_scroll(vc_cons[currcons].d, t, b, SM_UP, nr);
-}
-
-static void
-scrdown(int currcons, unsigned int t, unsigned int b, 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;
- }
- count = nr;
- while (count--) {
- s += video_num_columns;
- memsetw(s, video_erase_char, video_size_row);
- }
- has_scrolled = 1;
- if (currcons == fg_console)
- sw->con_scroll(vc_cons[currcons].d, t, b, SM_DOWN, nr);
-}
-
static void lf(int currcons)
{
/* don't scroll if above bottom of scrolling region, or
@@ -716,14 +806,14 @@
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 (currcons == fg_console) {
+ if (DO_UPDATE) {
/* do in two stages */
sw->con_clear(vc_cons[currcons].d, y, x, 1,
video_num_columns-x);
@@ -735,7 +825,7 @@
case 1: /* erase from start to cursor */
count = ((pos-origin)>>1)+1;
start = (unsigned short *) origin;
- if (currcons == fg_console) {
+ if (DO_UPDATE) {
/* do in two stages */
sw->con_clear(vc_cons[currcons].d, 0, 0, y,
video_num_columns);
@@ -746,7 +836,7 @@
case 2: /* erase whole display */
count = video_num_columns * video_num_lines;
start = (unsigned short *) origin;
- if (currcons == fg_console)
+ if (DO_UPDATE)
sw->con_clear(vc_cons[currcons].d, 0, 0,
video_num_lines,
video_num_columns);
@@ -754,41 +844,41 @@
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 (currcons == fg_console)
+ 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 (currcons == fg_console)
+ 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 (currcons == fg_console)
+ 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;
}
@@ -800,56 +890,12 @@
vpar++;
count = (vpar > video_num_columns-x) ? (video_num_columns-x) : vpar;
- memsetw((unsigned short *) pos, video_erase_char, 2 * count);
- if (currcons == fg_console)
+ 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)
-{
-/*
- * ++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
- *
- * ++Geert: TODO: Because the attributes have different meanings
- * for monochrome and color, they should really be converted if
- * can_do_color changes...
- */
- if (!can_do_color) {
- /* Special treatment for monochrome */
- attr = intensity |
- (underline ? 4 : 0) |
- ((reverse ^ decscnm) ? 8 : 0) |
- (blink ? 0x80 : 0);
- video_erase_char = ' ' | ((reverse ^ decscnm) ? 0x800 : 0);
- return;
- }
- 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 (decscnm)
- video_erase_char = (reverse_video_char(color) << 8) | ' ';
- else
- video_erase_char = (color << 8) | ' ';
-}
-
static void default_attr(int currcons)
{
intensity = 1;
@@ -903,264 +949,99 @@
toggle_meta = 0;
break;
case 12: /* ANSI X3.64-1979 (SCO-ish?)
- * Select second alternate font, toggle
- * high bit before displaying as ROM char.
- */
- translate = set_translate(IBMPC_MAP);
- disp_ctrl = 1;
- toggle_meta = 1;
- break;
- case 21:
- case 22:
- intensity = 1;
- break;
- case 24:
- underline = 0;
- break;
- case 25:
- blink = 0;
- break;
- case 27:
- reverse = 0;
- break;
- case 38: /* ANSI X3.64-1979 (SCO-ish?)
- * Enables underscore, white foreground
- * with white underscore (Linux - use
- * default foreground).
- */
- color = (def_color & 0x0f) | background;
- underline = 1;
- break;
- case 39: /* ANSI X3.64-1979 (SCO-ish?)
- * Disable underline option.
- * Reset colour to default? It did this
- * before...
- */
- color = (def_color & 0x0f) | background;
- underline = 0;
- break;
- case 49:
- color = (def_color & 0xf0) | foreground;
- break;
- default:
- if (par[i] >= 30 && par[i] <= 37)
- color = color_table[par[i]-30]
- | background;
- else if (par[i] >= 40 && par[i] <= 47)
- color = (color_table[par[i]-40]<<4)
- | foreground;
- break;
- }
- update_attr(currcons);
-}
-
-static void respond_string(const char * p, struct tty_struct * tty)
-{
- while (*p) {
- tty_insert_flip_char(tty, *p, 0);
- p++;
- }
- tty_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);
- respond_string(buf, tty);
-}
-
-static inline void status_report(struct tty_struct * tty)
-{
- respond_string("\033[0n", tty); /* Terminal ok */
-}
-
-static inline void respond_ID(struct tty_struct * tty)
-{
- respond_string(VT102ID, tty);
-}
-
-void mouse_report(struct tty_struct * tty, int butt, int mrx, int mry)
-{
- char buf[8];
-
- sprintf(buf, "\033[M%c%c%c", (char)(' ' + butt), (char)('!' + mrx),
- (char)('!' + mry));
- respond_string(buf, tty);
-}
-
-/* invoked via ioctl(TIOCLINUX) and through set_selection */
-int mouse_reporting(void)
-{
- int currcons = fg_console;
-
- 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);
- return p;
+ * Select second alternate font, toggle
+ * high bit before displaying as ROM char.
+ */
+ translate = set_translate(IBMPC_MAP);
+ disp_ctrl = 1;
+ toggle_meta = 1;
+ break;
+ case 21:
+ case 22:
+ intensity = 1;
+ break;
+ case 24:
+ underline = 0;
+ break;
+ case 25:
+ blink = 0;
+ break;
+ case 27:
+ reverse = 0;
+ break;
+ case 38: /* ANSI X3.64-1979 (SCO-ish?)
+ * Enables underscore, white foreground
+ * with white underscore (Linux - use
+ * default foreground).
+ */
+ color = (def_color & 0x0f) | background;
+ underline = 1;
+ break;
+ case 39: /* ANSI X3.64-1979 (SCO-ish?)
+ * Disable underline option.
+ * Reset colour to default? It did this
+ * before...
+ */
+ color = (def_color & 0x0f) | background;
+ underline = 0;
+ break;
+ case 49:
+ color = (def_color & 0xf0) | foreground;
+ break;
+ default:
+ if (par[i] >= 30 && par[i] <= 37)
+ color = color_table[par[i]-30]
+ | background;
+ else if (par[i] >= 40 && par[i] <= 47)
+ color = (color_table[par[i]-40]<<4)
+ | foreground;
+ break;
+ }
+ update_attr(currcons);
}
-static inline void visual_putc_attr(int currcons, unsigned short new,
- int yy, int xx)
+static void respond_string(const char * p, struct tty_struct * tty)
{
- unsigned short oldattr = attr;
- attr = new >> 8;
- sw->con_putc(vc_cons[currcons].d, new & 0xff, yy, xx);
- attr = oldattr;
-}
-
-static inline void visual_putc_attr_next(int currcons, unsigned short new,
- int *yy, int *xx)
-{
- attr = new >> 8;
- sw->con_putc(vc_cons[currcons].d, new & 0xff, *yy, *xx);
- if (++(*xx) == video_num_columns)
- *xx = 0, ++(*yy);
+ while (*p) {
+ tty_insert_flip_char(tty, *p, 0);
+ p++;
+ }
+ tty_schedule_flip(tty);
}
-
-/* Note: inverting the screen twice should revert to the original state */
-void invert_screen(int currcons, int offset, int count, int viewed)
+static void cursor_report(int currcons, struct tty_struct * tty)
{
- unsigned short *p;
- int xx = (offset >> 1) % video_num_columns;
- int yy = (offset >> 1) / video_num_columns;
- unsigned short oldattr = attr;
+ char buf[40];
- count /= 2;
- p = screenpos(currcons, offset, viewed);
- if (can_do_color)
- while (count--) {
- unsigned short old = scr_readw(p);
- unsigned short new = reverse_video_short(old);
- scr_writew(new, p);
- p++;
- if (currcons == fg_console)
- visual_putc_attr_next(currcons, new, &yy, &xx);
- }
- else
- while (count--) {
- unsigned short old = scr_readw(p);
- unsigned short new = reverse_video_short_mono(old);
- scr_writew(new, p);
- p++;
- if (currcons == fg_console)
- visual_putc_attr_next(currcons, new, &yy, &xx);
- }
- attr = oldattr;
+ sprintf(buf, "\033[%d;%dR", y + (decom ? top+1 : 1), x+1);
+ respond_string(buf, tty);
}
-/* used by selection: complement pointer position */
-void complement_pos(int currcons, int offset)
+static inline void status_report(struct tty_struct * tty)
{
- static unsigned short *p = NULL;
- static unsigned short old = 0;
- static unsigned short oldx = 0, oldy = 0;
-
- if (p) {
- scr_writew(old, p);
- if (currcons == fg_console)
- visual_putc_attr(currcons, old, oldy, oldx);
- }
- if (offset == -1)
- p = NULL;
- else {
- unsigned short new;
- p = screenpos(currcons, offset, 1);
- old = scr_readw(p);
- oldx = (offset >> 1) % video_num_columns;
- oldy = (offset >> 1) / video_num_columns;
- new = complement_video_short(old);
- scr_writew(new, p);
- if (currcons == fg_console)
- visual_putc_attr(currcons, new, oldy, oldx);
- }
+ respond_string("\033[0n", tty); /* Terminal ok */
}
-/* used by selection */
-unsigned short screen_word(int currcons, int offset, int viewed)
+static inline void respond_ID(struct tty_struct * tty)
{
- return scr_readw(screenpos(currcons, offset, viewed));
+ respond_string(VT102ID, tty);
}
-/* used by selection - convert a screen word to a glyph number */
-int scrw2glyph(unsigned short scr_word)
+void mouse_report(struct tty_struct * tty, int butt, int mrx, int mry)
{
- return ( video_mode_512ch )
- ? ((scr_word & 0x0800) >> 3) + (scr_word & 0x00ff)
- : scr_word & 0x00ff;
-}
+ char buf[8];
-/* 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);
+ sprintf(buf, "\033[M%c%c%c", (char)(' ' + butt), (char)('!' + mrx),
+ (char)('!' + mry));
+ respond_string(buf, tty);
}
-void getconsxy(int currcons, char *p)
+/* invoked via ioctl(TIOCLINUX) and through set_selection */
+int mouse_reporting(void)
{
- p[0] = x;
- p[1] = y;
-}
+ int currcons = fg_console;
-void putconsxy(int currcons, char *p)
-{
- gotoxy(currcons, p[0], p[1]);
- set_cursor(currcons);
+ return report_mouse;
}
static void set_mode(int currcons, int on_off)
@@ -1269,6 +1150,7 @@
bell_duration = DEFAULT_BELL_DURATION;
break;
case 12: /* bring specified console to the front */
+ /* FIXME: Use console_bh for switching! */
if (par[1] >= 1 && vc_cons_allocated(par[1]-1))
update_screen(par[1]-1);
break;
@@ -1281,56 +1163,12 @@
}
}
-static void insert_char(int currcons, unsigned int nr)
-{
- unsigned short *p, *q = (unsigned short *) pos;
-
- p = q + video_num_columns - nr - x;
- while (--p >= q)
- scr_writew(scr_readw(p), p + nr);
- memsetw(q, video_erase_char, nr*2);
- need_wrap = 0;
- if (currcons == fg_console) {
- 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 & 0x00ff),y,x+nr);
- attr = oldattr;
- }
-}
-
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 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++;
- }
- memsetw(p, video_erase_char, nr*2);
- need_wrap = 0;
- if (currcons == fg_console) {
- 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 & 0x00ff), y,
- video_num_columns-1-nr);
- attr = oldattr;
- }
-}
static void delete_line(int currcons, unsigned int nr)
{
@@ -1462,55 +1300,380 @@
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;
+ case 7:
+ if (bell_duration)
+ kd_mksound(bell_pitch, bell_duration);
+ return;
+ case 8:
+ bs(currcons);
+ return;
+ 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;
+ 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 (par[0])
+ cursor_type = par[0] | (par[1]<<8) | (par[2]<<16);
+ else
+ cursor_type = CUR_DEFAULT;
+ set_cursor(currcons);
+ return;
+ 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;
- console_num = MINOR(tty->device) - (tty->driver.minor_start);
- if (!vc_cons_allocated(console_num))
+ 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;
-#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 ESfunckey:
+ vc_state = ESnormal;
return;
- console_num = MINOR(tty->device) - (tty->driver.minor_start);
- if (!vc_cons_allocated(console_num))
+ case EShash:
+ vc_state = ESnormal;
+ if (c == '8') {
+ /* DEC screen alignment test. kludge :-) */
+ video_erase_char =
+ (video_erase_char & 0xff00) | 'E';
+ /* Arno:
+ * Doesn't work, because csi_J(c,2)
+ * calls con_clear and doesn't print
+ * the erase char.. FIXME
+ */
+ csi_J(currcons, 2);
+ video_erase_char =
+ (video_erase_char & 0xff00) | ' ';
+ }
return;
-#if !CONFIG_AP1000
- clr_vc_kbd_led(kbd_table + console_num, VC_SCROLLOCK);
- set_leds();
-#endif
-}
-
-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);
+ 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 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
@@ -1530,7 +1693,7 @@
}
/* undraw cursor first */
- if (currcons == fg_console)
+ if (DO_UPDATE)
hide_cursor(currcons);
/* clear the selection */
@@ -1627,516 +1790,80 @@
if (tc & ~console_charmask)
continue; /* Conversion failed */
+ if (need_wrap || decim)
+ FLUSH
if (need_wrap) {
cr(currcons);
lf(currcons);
}
-
- /* DPC: 1994-04-12
- * Speed up overstrike mode, using new putcs.
- *
- * P.S. I hate 8 spaces per tab! Use Emacs!
- */
-
- /* Only use this for the foreground console,
- where we really draw the chars */
-
- if (count > 2 &&
- !decim && !utf && currcons == fg_console) {
- char *p = putcs_buf;
- int putcs_count = 1;
- ushort nextx = x + 1;
-
- *p++ = tc;
- scr_writew((attr << 8) + tc,
- (unsigned short *)pos);
- pos+=2;
-
- if (nextx == video_num_columns) {
- sw->con_putc(vc_cons[currcons].d,
- *putcs_buf, y, x);
- pos-=2;
- need_wrap = decawm;
- continue;
- }
-
- /* TAB TAB TAB - Arghh!!!! */
-
- while (count) {
- enable_bh(CONSOLE_BH);
- if (from_user)
- get_user(c, buf);
- else
- c = *buf;
- disable_bh(CONSOLE_BH);
- tc = translate[toggle_meta ? (c|0x80) : c];
- if (!tc ||
- !(c >= 32
- || !(((disp_ctrl ? CTRL_ALWAYS
- : CTRL_ACTION) >> c) & 1)))
- break;
- tc = conv_uni_to_pc(tc);
- if (tc == -4)
- tc = conv_uni_to_pc(0xfffd);
- else if (tc == -3)
- tc = c;
-
- buf++; n++; count--;
- if (tc & ~console_charmask)
- continue; /* Conversion failed */
-
- *p++ = tc;
- scr_writew((attr << 8) + tc,
- (unsigned short *)pos);
- pos+=2;
- ++putcs_count;
- ++nextx;
- if (nextx == video_num_columns ||
- putcs_count == sizeof (putcs_buf))
- break;
- }
-
- sw->con_putcs(vc_cons[currcons].d,
- putcs_buf, putcs_count, y, x);
- if (nextx == video_num_columns) {
- pos-=2;
- x = video_num_columns-1;
- need_wrap = decawm;
- } else
- x += putcs_count;
- continue;
- }
-
- /* DPC: End of putcs support */
-
if (decim)
insert_char(currcons, 1);
- scr_writew( video_mode_512ch ?
+ scr_writew(c = video_mode_512ch ?
((attr & 0xf7) << 8) + ((tc & 0x100) << 3) +
(tc & 0x0ff) : (attr << 8) + tc,
(unsigned short *) pos);
- if (currcons == fg_console)
- sw->con_putc(vc_cons[currcons].d, tc, y, x);
- if (x == video_num_columns - 1)
+ 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 'c':
- if (par[0])
- cursor_type = par[0] | (par[1]<<8) | (par[2]<<16);
- else
- cursor_type = CUR_DEFAULT;
- set_cursor(currcons);
- 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';
- /* Arno:
- * Doesn't work, because csi_J(c,2)
- * calls con_clear and doesn't print
- * the erase char..
- */
- 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;
- }
+ /* FIXME: Handle tabs in a special way and use putcs for them as well */
+ 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;
+ if (want_console >= 0) {
+ if (want_console != 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 char *start = b;
+ const ushort *start;
ushort cnt = 0;
ushort myx = x;
@@ -2159,36 +1886,37 @@
/* undraw cursor first */
hide_cursor(currcons);
+
+ start = (ushort *)pos;
/* Contrived structure to try to emulate original need_wrap behaviour
* Problems caused when we have need_wrap set on '\n' character */
while (count--) {
c = *b++;
if (c == 10 || c == 13 || c == 8 || need_wrap) {
- if ((cnt = b - start - 1) > 0) {
+ if (cnt > 0) {
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 = b;
+ start = (ushort *)pos;
myx = x;
continue;
}
if (c != 13)
lf(currcons);
cr(currcons);
- if (c == 10 || c == 13) {
- start = b;
- myx = x;
- continue;
- }
- start = b-1;
+ start = (ushort *)pos;
myx = x;
+ if (c == 10 || c == 13)
+ continue;
}
scr_writew((attr << 8) + c, (unsigned short *) pos);
+ cnt++;
if (myx == video_num_columns - 1) {
need_wrap = 1;
continue;
@@ -2196,7 +1924,7 @@
pos+=2;
myx++;
}
- if ((cnt = b - start) > 0) {
+ if (cnt > 0) {
sw->con_putcs(vc_cons[currcons].d, start, cnt, y, x);
x += cnt;
if (x == video_num_columns) {
@@ -2204,32 +1932,116 @@
need_wrap = 1;
}
}
- set_cursor(currcons);
- poke_blanked_console();
- printing = 0;
+ set_cursor(currcons);
+ poke_blanked_console();
+ printing = 0;
+}
+
+static kdev_t vt_console_device(struct console *c)
+{
+ return MKDEV(TTY_MAJOR, c->index ? c->index : fg_console + 1);
+}
+
+struct console vt_console_driver = {
+ "tty",
+ vt_console_print,
+ NULL,
+ vt_console_device,
+ keyboard_wait_for_keypress,
+ do_unblank_screen,
+ NULL,
+ CON_PRINTBUFFER,
+ -1,
+ 0,
+ NULL
+};
+#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;
}
-static kdev_t vt_console_device(struct console *c)
+/*
+ * /dev/ttyN handling
+ */
+
+static int con_write(struct tty_struct * tty, int from_user,
+ const unsigned char *buf, int count)
{
- return MKDEV(TTY_MAJOR, c->index ? c->index : fg_console + 1);
+ int retval;
+
+ retval = do_con_write(tty, from_user, buf, count);
+ con_flush_chars(tty);
+
+ return retval;
}
-extern int keyboard_wait_for_keypress(struct console *);
+static void con_put_char(struct tty_struct *tty, unsigned char ch)
+{
+ do_con_write(tty, 0, &ch, 1);
+}
-struct console vt_console_driver = {
- "tty",
- vt_console_print,
- NULL,
- vt_console_device,
- keyboard_wait_for_keypress,
- do_unblank_screen,
- NULL,
- CON_PRINTBUFFER,
- -1,
- 0,
- NULL
-};
-#endif
+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
@@ -2247,9 +2059,76 @@
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;
+#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)
+ return;
+ console_num = MINOR(tty->device) - (tty->driver.minor_start);
+ if (!vc_cons_allocated(console_num))
+ return;
+#if !CONFIG_AP1000
+ clr_vc_kbd_led(kbd_table + console_num, VC_SCROLLOCK);
+ set_leds();
+#endif
+}
+
+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);
+}
+
+/*
+ * 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;
@@ -2257,9 +2136,8 @@
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] ;
@@ -2274,53 +2152,23 @@
}
/*
- * 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.
- *
*/
+
+struct tty_driver console_driver;
+static int console_refcount;
+
__initfunc(unsigned long con_init(unsigned long kmem_start))
{
const char *display_desc = NULL;
unsigned int currcons = 0;
- char q[2] = { 0, 1 };
if (conswitchp)
- kmem_start = conswitchp->con_startup(kmem_start,
- &display_desc);
+ display_desc = conswitchp->con_startup();
if (!display_desc) {
fg_console = 0;
return kmem_start;
@@ -2357,7 +2205,7 @@
panic("Couldn't register console driver\n");
#if CONFIG_AP1000
- return(kmem_start);
+ return kmem_start;
#endif
timer_table[BLANK_TIMER].fn = blank_screen;
@@ -2367,6 +2215,7 @@
timer_active |= 1<<BLANK_TIMER;
}
+ /* 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++) {
@@ -2377,34 +2226,25 @@
vt_cons[currcons] = (struct vt_struct *) kmem_start;
kmem_start += sizeof(struct vt_struct);
visual_init(currcons);
- vc_scrbuf[currcons] = (unsigned short *) kmem_start;
+ 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] ;
vc_cons[currcons].d->vc_palette[k++] = default_blu[j] ;
}
}
-
currcons = fg_console = 0;
-
- gotoxy(currcons,0,0);
+ save_screen();
+ gotoxy(currcons,x,y);
csi_J(currcons, 0);
update_screen(fg_console);
-
-#if 0
-/* The logo is too ugly to live */
- if (console_show_logo)
- q[1] += console_show_logo();
- conswitchp->con_putcs(vc_cons[fg_console].d, linux_logo_banner,
- sizeof(linux_logo_banner)-1, q[1]-1, q[0]);
- putconsxy(0, q);
-#endif
- sw->con_cursor(vc_cons[currcons].d, CM_DRAW);
- printk("Console: %s %s %ldx%ld",
+ set_cursor(currcons);
+ printk("Console: %s %s %dx%d",
can_do_color ? "colour" : "mono",
display_desc, video_num_columns, video_num_lines);
printable = 1;
@@ -2415,9 +2255,14 @@
#endif
init_bh(CONSOLE_BH, console_bh);
+
return kmem_start;
}
+/*
+ * Screen blanking
+ */
+
void set_vesa_blanking(unsigned long arg)
{
char *argp = (char *)arg + 1;
@@ -2480,9 +2325,8 @@
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;
+ save_screen();
sw->con_blank(1);
console_blanked = fg_console + 1;
@@ -2534,84 +2378,24 @@
do_unblank_screen();
}
-void update_screen(int new_console)
+void poke_blanked_console(void)
{
- int currcons = fg_console;
- int xx, yy, startx, attr_save;
- char *bufp;
- unsigned short *p;
- static int lock = 0;
-
- if (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();
-
- currcons = fg_console = new_console;
- sw->con_cursor (vc_cons[currcons].d, CM_ERASE);
- sw->con_switch (vc_cons[new_console].d);
- /* Update the screen contents */
- p = (unsigned short *)video_mem_start;
- attr_save = attr;
- for (yy = 0; yy < video_num_lines; yy++) {
- bufp = putcs_buf;
- for (startx = xx = 0; xx < video_num_columns; xx++) {
- if (attr != ((scr_readw(p) >> 8) & 0xff)) {
- if (bufp > putcs_buf)
- sw->con_putcs (vc_cons[currcons].d, putcs_buf,
- bufp - putcs_buf, yy, startx);
- startx = xx;
- bufp = putcs_buf;
- attr = (scr_readw(p) >> 8) & 0xff;
- }
- *bufp++ = scr_readw(p++);
- if (bufp == putcs_buf + sizeof (putcs_buf)) {
- sw->con_putcs (vc_cons[currcons].d, putcs_buf,
- bufp - putcs_buf, yy, startx);
- startx = xx + 1;
- bufp = putcs_buf;
- }
- }
- if (bufp > putcs_buf)
- sw->con_putcs (vc_cons[currcons].d, putcs_buf,
- bufp - putcs_buf, yy, startx);
- }
- set_cursor (currcons);
- attr = attr_save;
- 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 currcons;
- int i;
-
- currcons = MINOR(tty->device) - tty->driver.minor_start;
-
- i = vc_allocate(currcons);
- 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;
-}
void set_palette(void)
{
@@ -2673,7 +2457,7 @@
}
/*
- * PIO_FONT support.
+ * Font switching
*
* Currently we only support 8 pixels wide fonts, at a maximum height
* of 32 pixels. Userspace fontdata is stored with 32 bytes reserved
@@ -2687,63 +2471,111 @@
#define cmapsz 8192
-int set_get_font(unsigned char * arg, int set, int ch512)
+int con_set_font (char *arg, int w, int h, int chars)
{
- int i, unit, size;
- char *charmap;
-
- if (!arg)
- return -EINVAL;
-
-
- size = ch512 ? 2*cmapsz : cmapsz;
-
- charmap = (char *)kmalloc(size, GFP_USER);
+ int ch512;
+ int i = -EINVAL;
+ int s = cmapsz;
+ char *charmap;
+
+ if (vt_cons[fg_console]->vc_mode != KD_TEXT)
+ goto quit;
+ if (w != 8 || h < 0 || h >= 32)
+ goto quit;
+ if (chars == 256)
+ ch512 = 0;
+ else if (chars == 512) {
+ ch512 = 1;
+ s += s;
+ } else
+ goto quit;
+ s = ch512 ? 2*cmapsz : cmapsz;
+ charmap = kmalloc(s, GFP_USER);
+ if (!charmap)
+ return -ENOMEM;
+ i = -EFAULT;
+ if (copy_from_user(charmap, arg, s))
+ goto done;
+ if (!h) { /* No height given, try guessing */
+ for (h = 32; h > 0; h--)
+ for (i = 0; i < chars; i++)
+ if (charmap[32*i+h-1])
+ goto nonzero;
+ return -EINVAL; /* Empty fonts not allowed */
+ }
+ nonzero:
+ i = conswitchp->con_set_font(vc_cons[fg_console].d, w, h, charmap);
+ if ( !i ) {
+ hashtable_contents_valid = 0;
+ video_mode_512ch = ch512;
+ console_charmask = ch512 ? 0x1ff : 0x0ff;
+ }
+done:
+ kfree(charmap);
+quit:
+ return i;
+}
- if (set) {
- if (copy_from_user(charmap, arg, size)) {
- kfree(charmap);
- return -EFAULT;
- }
-
- for (unit = 32; unit > 0; unit--)
- for (i = 0; i < (ch512 ? 512 : 256); i++)
- if (charmap[32*i+unit-1])
- goto nonzero;
- nonzero:
- i = conswitchp->con_set_font(vc_cons[fg_console].d, 8, unit, charmap);
- } else {
- memset(charmap, 0, size);
- i = conswitchp->con_get_font(vc_cons[fg_console].d, &unit, &unit,
- charmap);
- if (i == 0 && copy_to_user(arg, charmap, size))
- i = -EFAULT;
- }
- kfree(charmap);
+int con_get_font (char *arg, int *w, int *h, int *chars)
+{
+ int num = video_mode_512ch ? 512 : 256;
+ char *charmap;
+ int s = video_mode_512ch ? 2*cmapsz : cmapsz;
+ int i;
- return i;
+ if (num < *chars)
+ return -ENOSPC;
+ if (vt_cons[fg_console]->vc_mode != KD_TEXT)
+ return -EINVAL;
+ *chars = num;
+ *w = 8;
+ charmap = kmalloc(s, GFP_USER);
+ if (!charmap)
+ return -ENOMEM;
+ memset(charmap, 0, s);
+ i = conswitchp->con_get_font(vc_cons[fg_console].d, w, h, charmap);
+ if (!i && copy_to_user(arg, charmap, s))
+ i = -EINVAL;
+ kfree(charmap);
+ return i;
}
/*
- * 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).
+ * Interface exported to selection and vcs.
*/
-int con_set_font (char *arg, int ch512)
+/* used by selection */
+unsigned short screen_word(int currcons, int offset, int viewed)
{
- int i;
+ return scr_readw(screenpos(currcons, offset, viewed));
+}
- i = set_get_font (arg,1,ch512);
- if ( !i ) {
- hashtable_contents_valid = 0;
- video_mode_512ch = ch512;
- console_charmask = ch512 ? 0x1ff : 0x0ff;
- }
- return i;
+/* 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);
}
+
+
+/*
+ * 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);
FUNET's LINUX-ADM group, linux-adm@nic.funet.fi
TCL-scripts by Sam Shen, slshen@lbl.gov