* - 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
- * - 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
*
* Removed console_lock, enabled interrupts across all console operations
* 13 March 2001, Andrew Morton
+ *
+ * Fixed UTF-8 mode so alternate charset modes always work according
+ * to control sequences interpreted in do_con_trol function
+ * preserving backward VT100 semigraphics compatibility,
+ * malformed UTF sequences represented as sequences of replacement glyphs,
+ * original codes or '?' as a last resort if replacement glyph is undefined
+ * by Adam Tla/lka <atlka@pg.gda.pl>, Aug 2006
*/
#include <linux/module.h>
#include <linux/mm.h>
#include <linux/console.h>
#include <linux/init.h>
-#include <linux/devfs_fs_kernel.h>
#include <linux/vt_kern.h>
#include <linux/selection.h>
#include <linux/tiocl.h>
#include <linux/consolemap.h>
#include <linux/timer.h>
#include <linux/interrupt.h>
-#include <linux/config.h>
#include <linux/workqueue.h>
#include <linux/bootmem.h>
#include <linux/pm.h>
#include <linux/font.h>
+#include <linux/bitops.h>
#include <asm/io.h>
#include <asm/system.h>
#include <asm/uaccess.h>
-#include <asm/bitops.h>
-#include "console_macros.h"
+#define MAX_NR_CON_DRIVER 16
+#define CON_DRIVER_FLAG_MODULE 1
+#define CON_DRIVER_FLAG_INIT 2
+#define CON_DRIVER_FLAG_ATTR 4
+struct con_driver {
+ const struct consw *con;
+ const char *desc;
+ struct device *dev;
+ int node;
+ int first;
+ int last;
+ int flag;
+};
+
+static struct con_driver registered_con_driver[MAX_NR_CON_DRIVER];
const struct consw *conswitchp;
/* A bitmap for codes <32. A bit of 1 indicates that the code
#define DEFAULT_BELL_PITCH 750
#define DEFAULT_BELL_DURATION (HZ/8)
-extern void vcs_make_devfs(struct tty_struct *tty);
-extern void vcs_remove_devfs(struct tty_struct *tty);
-
-extern void console_map_init(void);
-#ifdef CONFIG_PROM_CONSOLE
-extern void prom_con_init(void);
-#endif
-#ifdef CONFIG_MDA_CONSOLE
-extern int mda_console_init(void);
-#endif
-#ifdef CONFIG_FRAMEBUFFER_CONSOLE
-extern int fb_console_init(void);
-#endif
+extern void vcs_make_sysfs(struct tty_struct *tty);
+extern void vcs_remove_sysfs(struct tty_struct *tty);
struct vc vc_cons [MAX_NR_CONSOLES];
#endif
static int con_open(struct tty_struct *, struct file *);
-static void vc_init(unsigned int console, unsigned int rows,
+static void vc_init(struct vc_data *vc, unsigned int rows,
unsigned int cols, int do_clear);
-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);
+static void gotoxy(struct vc_data *vc, int new_x, int new_y);
+static void save_cur(struct vc_data *vc);
+static void reset_terminal(struct vc_data *vc, int do_clear);
static void con_flush_chars(struct tty_struct *tty);
-static void set_vesa_blanking(char __user *p);
-static void set_cursor(int currcons);
-static void hide_cursor(int currcons);
-static void console_callback(void *ignored);
+static int set_vesa_blanking(char __user *p);
+static void set_cursor(struct vc_data *vc);
+static void hide_cursor(struct vc_data *vc);
+static void console_callback(struct work_struct *ignored);
static void blank_screen_t(unsigned long dummy);
+static void set_palette(struct vc_data *vc);
static int printable; /* Is console ready for printing? */
static int blankinterval = 10*60*HZ;
static int vesa_off_interval;
-static DECLARE_WORK(console_work, console_callback, NULL);
+static DECLARE_WORK(console_work, console_callback);
/*
* fg_console is the current virtual console,
* Low-Level Functions
*/
-#define IS_FG (currcons == fg_console)
-#define IS_VISIBLE CON_IS_VISIBLE(vc_cons[currcons].d)
+#define IS_FG(vc) ((vc)->vc_num == fg_console)
#ifdef VT_BUF_VRAM_ONLY
-#define DO_UPDATE 0
+#define DO_UPDATE(vc) 0
#else
-#define DO_UPDATE IS_VISIBLE
+#define DO_UPDATE(vc) CON_IS_VISIBLE(vc)
#endif
-static int pm_con_request(struct pm_dev *dev, pm_request_t rqst, void *data);
-static struct pm_dev *pm_con;
-
-static inline unsigned short *screenpos(int currcons, int offset, int viewed)
+static inline unsigned short *screenpos(struct vc_data *vc, int offset, int viewed)
{
unsigned short *p;
if (!viewed)
- p = (unsigned short *)(origin + offset);
- else if (!sw->con_screen_pos)
- p = (unsigned short *)(visible_origin + offset);
+ p = (unsigned short *)(vc->vc_origin + offset);
+ else if (!vc->vc_sw->con_screen_pos)
+ p = (unsigned short *)(vc->vc_visible_origin + offset);
else
- p = sw->con_screen_pos(vc_cons[currcons].d, offset);
+ p = vc->vc_sw->con_screen_pos(vc, offset);
return p;
}
schedule_work(&console_work);
}
-static void scrup(int currcons, unsigned int t, unsigned int b, int nr)
+static void scrup(struct vc_data *vc, unsigned int t, unsigned int b, int nr)
{
unsigned short *d, *s;
if (t+nr >= b)
nr = b - t - 1;
- if (b > video_num_lines || t >= b || nr < 1)
+ if (b > vc->vc_rows || t >= b || nr < 1)
return;
- if (IS_VISIBLE && sw->con_scroll(vc_cons[currcons].d, t, b, SM_UP, nr))
+ if (CON_IS_VISIBLE(vc) && vc->vc_sw->con_scroll(vc, t, b, SM_UP, nr))
return;
- d = (unsigned short *) (origin+video_size_row*t);
- s = (unsigned short *) (origin+video_size_row*(t+nr));
- scr_memmovew(d, s, (b-t-nr) * video_size_row);
- scr_memsetw(d + (b-t-nr) * video_num_columns, video_erase_char, video_size_row*nr);
+ d = (unsigned short *)(vc->vc_origin + vc->vc_size_row * t);
+ s = (unsigned short *)(vc->vc_origin + vc->vc_size_row * (t + nr));
+ scr_memmovew(d, s, (b - t - nr) * vc->vc_size_row);
+ scr_memsetw(d + (b - t - nr) * vc->vc_cols, vc->vc_video_erase_char,
+ vc->vc_size_row * nr);
}
-static void
-scrdown(int currcons, unsigned int t, unsigned int b, int nr)
+static void scrdown(struct vc_data *vc, unsigned int t, unsigned int b, int nr)
{
unsigned short *s;
unsigned int step;
if (t+nr >= b)
nr = b - t - 1;
- if (b > video_num_lines || t >= b || nr < 1)
+ if (b > vc->vc_rows || t >= b || nr < 1)
return;
- if (IS_VISIBLE && sw->con_scroll(vc_cons[currcons].d, t, b, SM_DOWN, nr))
+ if (CON_IS_VISIBLE(vc) && vc->vc_sw->con_scroll(vc, 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);
+ s = (unsigned short *)(vc->vc_origin + vc->vc_size_row * t);
+ step = vc->vc_cols * nr;
+ scr_memmovew(s + step, s, (b - t - nr) * vc->vc_size_row);
+ scr_memsetw(s, vc->vc_video_erase_char, 2 * step);
}
-static void do_update_region(int currcons, unsigned long start, int count)
+static void do_update_region(struct vc_data *vc, unsigned long start, int count)
{
#ifndef VT_BUF_VRAM_ONLY
unsigned int xx, yy, offset;
u16 *p;
p = (u16 *) start;
- if (!sw->con_getxy) {
- offset = (start - origin) / 2;
- xx = offset % video_num_columns;
- yy = offset / video_num_columns;
+ if (!vc->vc_sw->con_getxy) {
+ offset = (start - vc->vc_origin) / 2;
+ xx = offset % vc->vc_cols;
+ yy = offset / vc->vc_cols;
} else {
int nxx, nyy;
- start = sw->con_getxy(vc_cons[currcons].d, start, &nxx, &nyy);
+ start = vc->vc_sw->con_getxy(vc, start, &nxx, &nyy);
xx = nxx; yy = nyy;
}
for(;;) {
u16 attrib = scr_readw(p) & 0xff00;
int startx = xx;
u16 *q = p;
- while (xx < video_num_columns && count) {
+ while (xx < vc->vc_cols && count) {
if (attrib != (scr_readw(p) & 0xff00)) {
if (p > q)
- sw->con_putcs(vc_cons[currcons].d, q, p-q, yy, startx);
+ vc->vc_sw->con_putcs(vc, q, p-q, yy, startx);
startx = xx;
q = p;
attrib = scr_readw(p) & 0xff00;
count--;
}
if (p > q)
- sw->con_putcs(vc_cons[currcons].d, q, p-q, yy, startx);
+ vc->vc_sw->con_putcs(vc, q, p-q, yy, startx);
if (!count)
break;
xx = 0;
yy++;
- if (sw->con_getxy) {
+ if (vc->vc_sw->con_getxy) {
p = (u16 *)start;
- start = sw->con_getxy(vc_cons[currcons].d, start, NULL, NULL);
+ start = vc->vc_sw->con_getxy(vc, start, NULL, NULL);
}
}
#endif
}
-void update_region(int currcons, unsigned long start, int count)
+void update_region(struct vc_data *vc, unsigned long start, int count)
{
WARN_CONSOLE_UNLOCKED();
- if (DO_UPDATE) {
- hide_cursor(currcons);
- do_update_region(currcons, start, count);
- set_cursor(currcons);
+ if (DO_UPDATE(vc)) {
+ hide_cursor(vc);
+ do_update_region(vc, start, count);
+ set_cursor(vc);
}
}
/* Structure of attributes is hardware-dependent */
-static u8 build_attr(int currcons, u8 _color, u8 _intensity, u8 _blink, u8 _underline, u8 _reverse)
+static u8 build_attr(struct vc_data *vc, 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);
+ if (vc->vc_sw->con_build_attr)
+ return vc->vc_sw->con_build_attr(vc, _color, _intensity, _blink, _underline, _reverse);
#ifndef VT_BUF_VRAM_ONLY
/*
* Bit 7 : blink
*/
{
- u8 a = color;
- if (!can_do_color)
+ u8 a = vc->vc_color;
+ if (!vc->vc_can_do_color)
return _intensity |
(_underline ? 4 : 0) |
(_reverse ? 8 : 0) |
(_blink ? 0x80 : 0);
if (_underline)
- a = (a & 0xf0) | ulcolor;
+ a = (a & 0xf0) | vc->vc_ulcolor;
else if (_intensity == 0)
- a = (a & 0xf0) | halfcolor;
+ a = (a & 0xf0) | vc->vc_ulcolor;
if (_reverse)
a = ((a) & 0x88) | ((((a) >> 4) | ((a) << 4)) & 0x77);
if (_blink)
a ^= 0x80;
if (_intensity == 2)
a ^= 0x08;
- if (hi_font_mask == 0x100)
+ if (vc->vc_hi_font_mask == 0x100)
a <<= 1;
return a;
}
#endif
}
-static void update_attr(int currcons)
+static void update_attr(struct vc_data *vc)
{
- attr = build_attr(currcons, color, intensity, blink, underline, reverse ^ decscnm);
- video_erase_char = (build_attr(currcons, color, 1, blink, 0, decscnm) << 8) | ' ';
+ vc->vc_attr = build_attr(vc, vc->vc_color, vc->vc_intensity, vc->vc_blink, vc->vc_underline, vc->vc_reverse ^ vc->vc_decscnm);
+ vc->vc_video_erase_char = (build_attr(vc, vc->vc_color, 1, vc->vc_blink, 0, vc->vc_decscnm) << 8) | ' ';
}
/* Note: inverting the screen twice should revert to the original state */
-
-void invert_screen(int currcons, int offset, int count, int viewed)
+void invert_screen(struct vc_data *vc, int offset, int count, int viewed)
{
unsigned short *p;
WARN_CONSOLE_UNLOCKED();
count /= 2;
- p = screenpos(currcons, offset, viewed);
- if (sw->con_invert_region)
- sw->con_invert_region(vc_cons[currcons].d, p, count);
+ p = screenpos(vc, offset, viewed);
+ if (vc->vc_sw->con_invert_region)
+ vc->vc_sw->con_invert_region(vc, p, count);
#ifndef VT_BUF_VRAM_ONLY
else {
u16 *q = p;
int cnt = count;
u16 a;
- if (!can_do_color) {
+ if (!vc->vc_can_do_color) {
while (cnt--) {
a = scr_readw(q);
a ^= 0x0800;
scr_writew(a, q);
q++;
}
- } else if (hi_font_mask == 0x100) {
+ } else if (vc->vc_hi_font_mask == 0x100) {
while (cnt--) {
a = scr_readw(q);
a = ((a) & 0x11ff) | (((a) & 0xe000) >> 4) | (((a) & 0x0e00) << 4);
}
}
#endif
- if (DO_UPDATE)
- do_update_region(currcons, (unsigned long) p, count);
+ if (DO_UPDATE(vc))
+ do_update_region(vc, (unsigned long) p, count);
}
/* used by selection: complement pointer position */
-void complement_pos(int currcons, int offset)
+void complement_pos(struct vc_data *vc, int offset)
{
- static unsigned short *p;
+ static int old_offset = -1;
static unsigned short old;
static unsigned short oldx, oldy;
WARN_CONSOLE_UNLOCKED();
- if (p) {
- scr_writew(old, p);
- if (DO_UPDATE)
- sw->con_putc(vc_cons[currcons].d, old, oldy, oldx);
+ if (old_offset != -1 && old_offset >= 0 &&
+ old_offset < vc->vc_screenbuf_size) {
+ scr_writew(old, screenpos(vc, old_offset, 1));
+ if (DO_UPDATE(vc))
+ vc->vc_sw->con_putc(vc, old, oldy, oldx);
}
- if (offset == -1)
- p = NULL;
- else {
+
+ old_offset = offset;
+
+ if (offset != -1 && offset >= 0 &&
+ offset < vc->vc_screenbuf_size) {
unsigned short new;
- p = screenpos(currcons, offset, 1);
+ unsigned short *p;
+ p = screenpos(vc, offset, 1);
old = scr_readw(p);
- new = old ^ complement_mask;
+ new = old ^ vc->vc_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);
+ if (DO_UPDATE(vc)) {
+ oldx = (offset >> 1) % vc->vc_cols;
+ oldy = (offset >> 1) / vc->vc_cols;
+ vc->vc_sw->con_putc(vc, new, oldy, oldx);
}
}
+
}
-static void insert_char(int currcons, unsigned int nr)
+static void insert_char(struct vc_data *vc, unsigned int nr)
{
- unsigned short *p, *q = (unsigned short *) pos;
+ unsigned short *p, *q = (unsigned short *)vc->vc_pos;
- p = q + video_num_columns - nr - x;
+ p = q + vc->vc_cols - nr - vc->vc_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;
+ scr_memsetw(q, vc->vc_video_erase_char, nr * 2);
+ vc->vc_need_wrap = 0;
+ if (DO_UPDATE(vc)) {
+ unsigned short oldattr = vc->vc_attr;
+ vc->vc_sw->con_bmove(vc, vc->vc_y, vc->vc_x, vc->vc_y, vc->vc_x + nr, 1,
+ vc->vc_cols - vc->vc_x - nr);
+ vc->vc_attr = vc->vc_video_erase_char >> 8;
while (nr--)
- sw->con_putc(vc_cons[currcons].d,
- video_erase_char,y,x+nr);
- attr = oldattr;
+ vc->vc_sw->con_putc(vc, vc->vc_video_erase_char, vc->vc_y, vc->vc_x + nr);
+ vc->vc_attr = oldattr;
}
}
-static void delete_char(int currcons, unsigned int nr)
+static void delete_char(struct vc_data *vc, unsigned int nr)
{
- unsigned int i = x;
- unsigned short *p = (unsigned short *) pos;
+ unsigned int i = vc->vc_x;
+ unsigned short *p = (unsigned short *)vc->vc_pos;
- while (++i <= video_num_columns - nr) {
+ while (++i <= vc->vc_cols - 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;
+ scr_memsetw(p, vc->vc_video_erase_char, nr * 2);
+ vc->vc_need_wrap = 0;
+ if (DO_UPDATE(vc)) {
+ unsigned short oldattr = vc->vc_attr;
+ vc->vc_sw->con_bmove(vc, vc->vc_y, vc->vc_x + nr, vc->vc_y, vc->vc_x, 1,
+ vc->vc_cols - vc->vc_x - nr);
+ vc->vc_attr = vc->vc_video_erase_char >> 8;
while (nr--)
- sw->con_putc(vc_cons[currcons].d,
- video_erase_char, y,
- video_num_columns-1-nr);
- attr = oldattr;
+ vc->vc_sw->con_putc(vc, vc->vc_video_erase_char, vc->vc_y,
+ vc->vc_cols - 1 - nr);
+ vc->vc_attr = oldattr;
}
}
static int softcursor_original;
-static void add_softcursor(int currcons)
+static void add_softcursor(struct vc_data *vc)
{
- int i = scr_readw((u16 *) pos);
- u32 type = cursor_type;
+ int i = scr_readw((u16 *) vc->vc_pos);
+ u32 type = vc->vc_cursor_type;
if (! (type & 0x10)) return;
if (softcursor_original != -1) return;
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);
+ scr_writew(i, (u16 *) vc->vc_pos);
+ if (DO_UPDATE(vc))
+ vc->vc_sw->con_putc(vc, i, vc->vc_y, vc->vc_x);
}
-static void hide_softcursor(int currcons)
+static void hide_softcursor(struct vc_data *vc)
{
if (softcursor_original != -1) {
- scr_writew(softcursor_original,(u16 *) pos);
- if (DO_UPDATE)
- sw->con_putc(vc_cons[currcons].d, softcursor_original, y, x);
+ scr_writew(softcursor_original, (u16 *)vc->vc_pos);
+ if (DO_UPDATE(vc))
+ vc->vc_sw->con_putc(vc, softcursor_original,
+ vc->vc_y, vc->vc_x);
softcursor_original = -1;
}
}
-static void hide_cursor(int currcons)
+static void hide_cursor(struct vc_data *vc)
{
- if (currcons == sel_cons)
+ if (vc == sel_cons)
clear_selection();
- sw->con_cursor(vc_cons[currcons].d,CM_ERASE);
- hide_softcursor(currcons);
+ vc->vc_sw->con_cursor(vc, CM_ERASE);
+ hide_softcursor(vc);
}
-static void set_cursor(int currcons)
+static void set_cursor(struct vc_data *vc)
{
- 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);
+ if (!IS_FG(vc) || console_blanked ||
+ vc->vc_mode == KD_GRAPHICS)
+ return;
+ if (vc->vc_deccm) {
+ if (vc == sel_cons)
+ clear_selection();
+ add_softcursor(vc);
+ if ((vc->vc_cursor_type & 0x0f) != 1)
+ vc->vc_sw->con_cursor(vc, CM_DRAW);
+ } else
+ hide_cursor(vc);
}
-static void set_origin(int currcons)
+static void set_origin(struct vc_data *vc)
{
WARN_CONSOLE_UNLOCKED();
- 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;
+ if (!CON_IS_VISIBLE(vc) ||
+ !vc->vc_sw->con_set_origin ||
+ !vc->vc_sw->con_set_origin(vc))
+ vc->vc_origin = (unsigned long)vc->vc_screenbuf;
+ vc->vc_visible_origin = vc->vc_origin;
+ vc->vc_scr_end = vc->vc_origin + vc->vc_screenbuf_size;
+ vc->vc_pos = vc->vc_origin + vc->vc_size_row * vc->vc_y + 2 * vc->vc_x;
}
-static inline void save_screen(int currcons)
+static inline void save_screen(struct vc_data *vc)
{
WARN_CONSOLE_UNLOCKED();
- if (sw->con_save_screen)
- sw->con_save_screen(vc_cons[currcons].d);
+ if (vc->vc_sw->con_save_screen)
+ vc->vc_sw->con_save_screen(vc);
}
/*
* Redrawing of screen
*/
-void redraw_screen(int new_console, int is_switch)
+static void clear_buffer_attributes(struct vc_data *vc)
{
- int redraw = 1;
- int currcons, old_console;
+ unsigned short *p = (unsigned short *)vc->vc_origin;
+ int count = vc->vc_screenbuf_size / 2;
+ int mask = vc->vc_hi_font_mask | 0xff;
+
+ for (; count > 0; count--, p++) {
+ scr_writew((scr_readw(p)&mask) | (vc->vc_video_erase_char & ~mask), p);
+ }
+}
+
+void redraw_screen(struct vc_data *vc, int is_switch)
+{
+ int redraw = 0;
WARN_CONSOLE_UNLOCKED();
- if (!vc_cons_allocated(new_console)) {
+ if (!vc) {
/* strange ... */
/* printk("redraw_screen: tty %d not allocated ??\n", new_console+1); */
return;
}
if (is_switch) {
- currcons = fg_console;
- hide_cursor(currcons);
- if (fg_console != new_console) {
- struct vc_data **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) {
- save_screen(currcons);
- set_origin(currcons);
- }
- currcons = new_console;
- if (old_console == new_console)
- redraw = 0;
+ struct vc_data *old_vc = vc_cons[fg_console].d;
+ if (old_vc == vc)
+ return;
+ if (!CON_IS_VISIBLE(vc))
+ redraw = 1;
+ *vc->vc_display_fg = vc;
+ fg_console = vc->vc_num;
+ hide_cursor(old_vc);
+ if (!CON_IS_VISIBLE(old_vc)) {
+ save_screen(old_vc);
+ set_origin(old_vc);
}
} else {
- currcons = new_console;
- hide_cursor(currcons);
+ hide_cursor(vc);
+ redraw = 1;
}
if (redraw) {
int update;
- set_origin(currcons);
- update = sw->con_switch(vc_cons[currcons].d);
- set_palette(currcons);
- if (update && vcmode != KD_GRAPHICS)
- do_update_region(currcons, origin, screenbuf_size/2);
+ int old_was_color = vc->vc_can_do_color;
+
+ set_origin(vc);
+ update = vc->vc_sw->con_switch(vc);
+ set_palette(vc);
+ /*
+ * If console changed from mono<->color, the best we can do
+ * is to clear the buffer attributes. As it currently stands,
+ * rebuilding new attributes from the old buffer is not doable
+ * without overly complex code.
+ */
+ if (old_was_color != vc->vc_can_do_color) {
+ update_attr(vc);
+ clear_buffer_attributes(vc);
+ }
+ if (update && vc->vc_mode != KD_GRAPHICS)
+ do_update_region(vc, vc->vc_origin, vc->vc_screenbuf_size / 2);
}
- set_cursor(currcons);
+ set_cursor(vc);
if (is_switch) {
set_leds();
compute_shiftstate();
return (i < MAX_NR_CONSOLES && vc_cons[i].d);
}
-static void visual_init(int currcons, int init)
+static void visual_init(struct vc_data *vc, int num, int init)
{
- /* ++Geert: sw->con_init determines console size */
- if (sw)
- module_put(sw->owner);
- sw = conswitchp;
+ /* ++Geert: vc->vc_sw->con_init determines console size */
+ if (vc->vc_sw)
+ module_put(vc->vc_sw->owner);
+ vc->vc_sw = conswitchp;
#ifndef VT_SINGLE_DRIVER
- if (con_driver_map[currcons])
- sw = con_driver_map[currcons];
+ if (con_driver_map[num])
+ vc->vc_sw = con_driver_map[num];
#endif
- __module_get(sw->owner);
- 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;
- can_do_color = 0;
- sw->con_init(vc_cons[currcons].d, init);
- if (!complement_mask)
- complement_mask = can_do_color ? 0x7700 : 0x0800;
- s_complement_mask = complement_mask;
- video_size_row = video_num_columns<<1;
- screenbuf_size = video_num_lines*video_size_row;
+ __module_get(vc->vc_sw->owner);
+ vc->vc_num = num;
+ vc->vc_display_fg = &master_display_fg;
+ vc->vc_uni_pagedir_loc = &vc->vc_uni_pagedir;
+ vc->vc_uni_pagedir = 0;
+ vc->vc_hi_font_mask = 0;
+ vc->vc_complement_mask = 0;
+ vc->vc_can_do_color = 0;
+ vc->vc_sw->con_init(vc, init);
+ if (!vc->vc_complement_mask)
+ vc->vc_complement_mask = vc->vc_can_do_color ? 0x7700 : 0x0800;
+ vc->vc_s_complement_mask = vc->vc_complement_mask;
+ vc->vc_size_row = vc->vc_cols << 1;
+ vc->vc_screenbuf_size = vc->vc_rows * vc->vc_size_row;
}
int vc_allocate(unsigned int currcons) /* return 0 on success */
if (currcons >= MAX_NR_CONSOLES)
return -ENXIO;
if (!vc_cons[currcons].d) {
- long p, q;
+ struct vc_data *vc;
/* prevent users from taking too much memory */
if (currcons >= MAX_NR_USER_CONSOLES && !capable(CAP_SYS_RESOURCE))
/* 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)
+ vc = kmalloc(sizeof(struct vc_data), GFP_KERNEL);
+ if (!vc)
return -ENOMEM;
- memset((void *)p, 0, structsize);
- vc_cons[currcons].d = (struct vc_data *)p;
- vt_cons[currcons] = (struct vt_struct *)(p+sizeof(struct vc_data));
- visual_init(currcons, 1);
- if (!*vc_cons[currcons].d->vc_uni_pagedir_loc)
- con_set_default_unimap(currcons);
- q = (long)kmalloc(screenbuf_size, GFP_KERNEL);
- if (!q) {
- kfree((char *) p);
+ memset(vc, 0, sizeof(*vc));
+ vc_cons[currcons].d = vc;
+ visual_init(vc, currcons, 1);
+ if (!*vc->vc_uni_pagedir_loc)
+ con_set_default_unimap(vc);
+ if (!vc->vc_kmalloced)
+ vc->vc_screenbuf = kmalloc(vc->vc_screenbuf_size, GFP_KERNEL);
+ if (!vc->vc_screenbuf) {
+ kfree(vc);
vc_cons[currcons].d = NULL;
- vt_cons[currcons] = NULL;
return -ENOMEM;
}
- screenbuf = (unsigned short *) q;
- kmalloced = 1;
- vc_init(currcons, video_num_lines, video_num_columns, 1);
-
- if (!pm_con) {
- pm_con = pm_register(PM_SYS_DEV,
- PM_SYS_VGA,
- pm_con_request);
- }
+ vc->vc_kmalloced = 1;
+ vc_init(vc, vc->vc_rows, vc->vc_cols, 1);
}
return 0;
}
-inline int resize_screen(int currcons, int width, int height)
+static inline int resize_screen(struct vc_data *vc, int width, int height)
{
/* Resizes the resolution of the display adapater */
int err = 0;
- if (vcmode != KD_GRAPHICS && sw->con_resize)
- err = sw->con_resize(vc_cons[currcons].d, width, height);
+ if (vc->vc_mode != KD_GRAPHICS && vc->vc_sw->con_resize)
+ err = vc->vc_sw->con_resize(vc, width, height);
return err;
}
* [this is to be used together with some user program
* like resize that changes the hardware videomode]
*/
-int vc_resize(int currcons, unsigned int cols, unsigned int lines)
+#define VC_RESIZE_MAXCOL (32767)
+#define VC_RESIZE_MAXROW (32767)
+int vc_resize(struct vc_data *vc, unsigned int cols, unsigned int lines)
{
unsigned long old_origin, new_origin, new_scr_end, rlth, rrem, err = 0;
unsigned int old_cols, old_rows, old_row_size, old_screen_size;
unsigned int new_cols, new_rows, new_row_size, new_screen_size;
+ unsigned int end;
unsigned short *newscreen;
WARN_CONSOLE_UNLOCKED();
- if (!vc_cons_allocated(currcons))
+ if (!vc)
return -ENXIO;
- new_cols = (cols ? cols : video_num_columns);
- new_rows = (lines ? lines : video_num_lines);
+ if (cols > VC_RESIZE_MAXCOL || lines > VC_RESIZE_MAXROW)
+ return -EINVAL;
+
+ new_cols = (cols ? cols : vc->vc_cols);
+ new_rows = (lines ? lines : vc->vc_rows);
new_row_size = new_cols << 1;
new_screen_size = new_row_size * new_rows;
- if (new_cols == video_num_columns && new_rows == video_num_lines)
+ if (new_cols == vc->vc_cols && new_rows == vc->vc_rows)
return 0;
- newscreen = (unsigned short *) kmalloc(new_screen_size, GFP_USER);
+ newscreen = kmalloc(new_screen_size, GFP_USER);
if (!newscreen)
return -ENOMEM;
- old_rows = video_num_lines;
- old_cols = video_num_columns;
- old_row_size = video_size_row;
- old_screen_size = screenbuf_size;
+ old_rows = vc->vc_rows;
+ old_cols = vc->vc_cols;
+ old_row_size = vc->vc_size_row;
+ old_screen_size = vc->vc_screenbuf_size;
- err = resize_screen(currcons, new_cols, new_rows);
+ err = resize_screen(vc, new_cols, new_rows);
if (err) {
kfree(newscreen);
return err;
}
- video_num_lines = new_rows;
- video_num_columns = new_cols;
- video_size_row = new_row_size;
- screenbuf_size = new_screen_size;
+ vc->vc_rows = new_rows;
+ vc->vc_cols = new_cols;
+ vc->vc_size_row = new_row_size;
+ vc->vc_screenbuf_size = new_screen_size;
rlth = min(old_row_size, new_row_size);
rrem = new_row_size - rlth;
- old_origin = origin;
+ old_origin = vc->vc_origin;
new_origin = (long) newscreen;
new_scr_end = new_origin + new_screen_size;
- if (new_rows < old_rows)
- old_origin += (old_rows - new_rows) * old_row_size;
- update_attr(currcons);
+ if (vc->vc_y > new_rows) {
+ if (old_rows - vc->vc_y < new_rows) {
+ /*
+ * Cursor near the bottom, copy contents from the
+ * bottom of buffer
+ */
+ old_origin += (old_rows - new_rows) * old_row_size;
+ end = vc->vc_scr_end;
+ } else {
+ /*
+ * Cursor is in no man's land, copy 1/2 screenful
+ * from the top and bottom of cursor position
+ */
+ old_origin += (vc->vc_y - new_rows/2) * old_row_size;
+ end = old_origin + (old_row_size * new_rows);
+ }
+ } else
+ /*
+ * Cursor near the top, copy contents from the top of buffer
+ */
+ end = (old_rows > new_rows) ? old_origin +
+ (old_row_size * new_rows) :
+ vc->vc_scr_end;
+
+ update_attr(vc);
- while (old_origin < scr_end) {
- scr_memcpyw((unsigned short *) new_origin, (unsigned short *) old_origin, rlth);
+ while (old_origin < end) {
+ scr_memcpyw((unsigned short *) new_origin,
+ (unsigned short *) old_origin, rlth);
if (rrem)
- scr_memsetw((void *)(new_origin + rlth), video_erase_char, rrem);
+ scr_memsetw((void *)(new_origin + rlth),
+ vc->vc_video_erase_char, rrem);
old_origin += old_row_size;
new_origin += new_row_size;
}
if (new_scr_end > new_origin)
- scr_memsetw((void *) new_origin, video_erase_char, new_scr_end - new_origin);
- if (kmalloced)
- kfree(screenbuf);
- screenbuf = newscreen;
- kmalloced = 1;
- screenbuf_size = new_screen_size;
- set_origin(currcons);
+ scr_memsetw((void *)new_origin, vc->vc_video_erase_char,
+ new_scr_end - new_origin);
+ if (vc->vc_kmalloced)
+ kfree(vc->vc_screenbuf);
+ vc->vc_screenbuf = newscreen;
+ vc->vc_kmalloced = 1;
+ vc->vc_screenbuf_size = new_screen_size;
+ set_origin(vc);
/* do part of a reset_terminal() */
- top = 0;
- bottom = video_num_lines;
- gotoxy(currcons, x, y);
- save_cur(currcons);
+ vc->vc_top = 0;
+ vc->vc_bottom = vc->vc_rows;
+ gotoxy(vc, vc->vc_x, vc->vc_y);
+ save_cur(vc);
- if (vc_cons[currcons].d->vc_tty) {
- struct winsize ws, *cws = &vc_cons[currcons].d->vc_tty->winsize;
+ if (vc->vc_tty) {
+ struct winsize ws, *cws = &vc->vc_tty->winsize;
memset(&ws, 0, sizeof(ws));
- ws.ws_row = video_num_lines;
- ws.ws_col = video_num_columns;
- ws.ws_ypixel = video_scan_lines;
+ ws.ws_row = vc->vc_rows;
+ ws.ws_col = vc->vc_cols;
+ ws.ws_ypixel = vc->vc_scan_lines;
if ((ws.ws_row != cws->ws_row || ws.ws_col != cws->ws_col) &&
- vc_cons[currcons].d->vc_tty->pgrp > 0)
- kill_pg(vc_cons[currcons].d->vc_tty->pgrp, SIGWINCH, 1);
+ vc->vc_tty->pgrp > 0)
+ kill_pg(vc->vc_tty->pgrp, SIGWINCH, 1);
*cws = ws;
}
- if (IS_VISIBLE)
- update_screen(currcons);
+ if (CON_IS_VISIBLE(vc))
+ update_screen(vc);
return err;
}
+int vc_lock_resize(struct vc_data *vc, unsigned int cols, unsigned int lines)
+{
+ int rc;
+
+ acquire_console_sem();
+ rc = vc_resize(vc, cols, lines);
+ release_console_sem();
+ return rc;
+}
-void vc_disallocate(unsigned int currcons)
+void vc_deallocate(unsigned int currcons)
{
WARN_CONSOLE_UNLOCKED();
if (vc_cons_allocated(currcons)) {
- sw->con_deinit(vc_cons[currcons].d);
- if (kmalloced)
- kfree(screenbuf);
- if (currcons >= MIN_NR_CONSOLES)
- kfree(vc_cons[currcons].d);
- vc_cons[currcons].d = NULL;
+ struct vc_data *vc = vc_cons[currcons].d;
+ vc->vc_sw->con_deinit(vc);
+ put_pid(vc->vt_pid);
+ module_put(vc->vc_sw->owner);
+ if (vc->vc_kmalloced)
+ kfree(vc->vc_screenbuf);
+ if (currcons >= MIN_NR_CONSOLES)
+ kfree(vc);
+ 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)
-#define is_kbd(x) vc_kbd_mode(kbd_table+currcons,x)
+#define set_kbd(vc, x) set_vc_kbd_mode(kbd_table + (vc)->vc_num, (x))
+#define clr_kbd(vc, x) clr_vc_kbd_mode(kbd_table + (vc)->vc_num, (x))
+#define is_kbd(vc, x) vc_kbd_mode(kbd_table + (vc)->vc_num, (x))
#define decarm VC_REPEAT
#define decckm VC_CKMODE
* might also be negative. If the given position is out of
* bounds, the cursor is placed at the nearest margin.
*/
-static void gotoxy(int currcons, int new_x, int new_y)
+static void gotoxy(struct vc_data *vc, int new_x, int new_y)
{
int min_y, max_y;
if (new_x < 0)
- x = 0;
- else
- if (new_x >= video_num_columns)
- x = video_num_columns - 1;
+ vc->vc_x = 0;
+ else {
+ if (new_x >= vc->vc_cols)
+ vc->vc_x = vc->vc_cols - 1;
else
- x = new_x;
- if (decom) {
- min_y = top;
- max_y = bottom;
+ vc->vc_x = new_x;
+ }
+
+ if (vc->vc_decom) {
+ min_y = vc->vc_top;
+ max_y = vc->vc_bottom;
} else {
min_y = 0;
- max_y = video_num_lines;
+ max_y = vc->vc_rows;
}
if (new_y < min_y)
- y = min_y;
+ vc->vc_y = min_y;
else if (new_y >= max_y)
- y = max_y - 1;
+ vc->vc_y = max_y - 1;
else
- y = new_y;
- pos = origin + y*video_size_row + (x<<1);
- need_wrap = 0;
+ vc->vc_y = new_y;
+ vc->vc_pos = vc->vc_origin + vc->vc_y * vc->vc_size_row + (vc->vc_x<<1);
+ vc->vc_need_wrap = 0;
}
/* for absolute user moves, when decom is set */
-static void gotoxay(int currcons, int new_x, int new_y)
+static void gotoxay(struct vc_data *vc, int new_x, int new_y)
{
- gotoxy(currcons, new_x, decom ? (top+new_y) : new_y);
+ gotoxy(vc, new_x, vc->vc_decom ? (vc->vc_top + new_y) : new_y);
}
-void scrollback(int lines)
+void scrollback(struct vc_data *vc, int lines)
{
- int currcons = fg_console;
-
if (!lines)
- lines = video_num_lines/2;
+ lines = vc->vc_rows / 2;
scrolldelta(-lines);
}
-void scrollfront(int lines)
+void scrollfront(struct vc_data *vc, int lines)
{
- int currcons = fg_console;
-
if (!lines)
- lines = video_num_lines/2;
+ lines = vc->vc_rows / 2;
scrolldelta(lines);
}
-static void lf(int currcons)
+static void lf(struct vc_data *vc)
{
/* don't scroll if above bottom of scrolling region, or
* if below scrolling region
*/
- if (y+1 == bottom)
- scrup(currcons,top,bottom,1);
- else if (y < video_num_lines-1) {
- y++;
- pos += video_size_row;
+ if (vc->vc_y + 1 == vc->vc_bottom)
+ scrup(vc, vc->vc_top, vc->vc_bottom, 1);
+ else if (vc->vc_y < vc->vc_rows - 1) {
+ vc->vc_y++;
+ vc->vc_pos += vc->vc_size_row;
}
- need_wrap = 0;
+ vc->vc_need_wrap = 0;
}
-static void ri(int currcons)
+static void ri(struct vc_data *vc)
{
/* don't scroll if below top of scrolling region, or
* if above scrolling region
*/
- if (y == top)
- scrdown(currcons,top,bottom,1);
- else if (y > 0) {
- y--;
- pos -= video_size_row;
+ if (vc->vc_y == vc->vc_top)
+ scrdown(vc, vc->vc_top, vc->vc_bottom, 1);
+ else if (vc->vc_y > 0) {
+ vc->vc_y--;
+ vc->vc_pos -= vc->vc_size_row;
}
- need_wrap = 0;
+ vc->vc_need_wrap = 0;
}
-static inline void cr(int currcons)
+static inline void cr(struct vc_data *vc)
{
- pos -= x<<1;
- need_wrap = x = 0;
+ vc->vc_pos -= vc->vc_x << 1;
+ vc->vc_need_wrap = vc->vc_x = 0;
}
-static inline void bs(int currcons)
+static inline void bs(struct vc_data *vc)
{
- if (x) {
- pos -= 2;
- x--;
- need_wrap = 0;
+ if (vc->vc_x) {
+ vc->vc_pos -= 2;
+ vc->vc_x--;
+ vc->vc_need_wrap = 0;
}
}
-static inline void del(int currcons)
+static inline void del(struct vc_data *vc)
{
/* ignored */
}
-static void csi_J(int currcons, int vpar)
+static void csi_J(struct vc_data *vc, int vpar)
{
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) {
+ count = (vc->vc_scr_end - vc->vc_pos) >> 1;
+ start = (unsigned short *)vc->vc_pos;
+ if (DO_UPDATE(vc)) {
/* 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);
+ vc->vc_sw->con_clear(vc, vc->vc_y, vc->vc_x, 1,
+ vc->vc_cols - vc->vc_x);
+ vc->vc_sw->con_clear(vc, vc->vc_y + 1, 0,
+ vc->vc_rows - vc->vc_y - 1,
+ vc->vc_cols);
}
break;
case 1: /* erase from start to cursor */
- count = ((pos-origin)>>1)+1;
- start = (unsigned short *) origin;
- if (DO_UPDATE) {
+ count = ((vc->vc_pos - vc->vc_origin) >> 1) + 1;
+ start = (unsigned short *)vc->vc_origin;
+ if (DO_UPDATE(vc)) {
/* 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);
+ vc->vc_sw->con_clear(vc, 0, 0, vc->vc_y,
+ vc->vc_cols);
+ vc->vc_sw->con_clear(vc, vc->vc_y, 0, 1,
+ vc->vc_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);
+ count = vc->vc_cols * vc->vc_rows;
+ start = (unsigned short *)vc->vc_origin;
+ if (DO_UPDATE(vc))
+ vc->vc_sw->con_clear(vc, 0, 0,
+ vc->vc_rows,
+ vc->vc_cols);
break;
default:
return;
}
- scr_memsetw(start, video_erase_char, 2*count);
- need_wrap = 0;
+ scr_memsetw(start, vc->vc_video_erase_char, 2 * count);
+ vc->vc_need_wrap = 0;
}
-static void csi_K(int currcons, int vpar)
+static void csi_K(struct vc_data *vc, int vpar)
{
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);
+ count = vc->vc_cols - vc->vc_x;
+ start = (unsigned short *)vc->vc_pos;
+ if (DO_UPDATE(vc))
+ vc->vc_sw->con_clear(vc, vc->vc_y, vc->vc_x, 1,
+ vc->vc_cols - vc->vc_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);
+ start = (unsigned short *)(vc->vc_pos - (vc->vc_x << 1));
+ count = vc->vc_x + 1;
+ if (DO_UPDATE(vc))
+ vc->vc_sw->con_clear(vc, vc->vc_y, 0, 1,
+ vc->vc_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);
+ start = (unsigned short *)(vc->vc_pos - (vc->vc_x << 1));
+ count = vc->vc_cols;
+ if (DO_UPDATE(vc))
+ vc->vc_sw->con_clear(vc, vc->vc_y, 0, 1,
+ vc->vc_cols);
break;
default:
return;
}
- scr_memsetw(start, video_erase_char, 2 * count);
- need_wrap = 0;
+ scr_memsetw(start, vc->vc_video_erase_char, 2 * count);
+ vc->vc_need_wrap = 0;
}
-static void csi_X(int currcons, int vpar) /* erase the following vpar positions */
+static void csi_X(struct vc_data *vc, 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;
+ count = (vpar > vc->vc_cols - vc->vc_x) ? (vc->vc_cols - vc->vc_x) : 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;
+ scr_memsetw((unsigned short *)vc->vc_pos, vc->vc_video_erase_char, 2 * count);
+ if (DO_UPDATE(vc))
+ vc->vc_sw->con_clear(vc, vc->vc_y, vc->vc_x, 1, count);
+ vc->vc_need_wrap = 0;
}
-static void default_attr(int currcons)
+static void default_attr(struct vc_data *vc)
{
- intensity = 1;
- underline = 0;
- reverse = 0;
- blink = 0;
- color = def_color;
+ vc->vc_intensity = 1;
+ vc->vc_underline = 0;
+ vc->vc_reverse = 0;
+ vc->vc_blink = 0;
+ vc->vc_color = vc->vc_def_color;
}
/* console_sem is held */
-static void csi_m(int currcons)
+static void csi_m(struct vc_data *vc)
{
int i;
- for (i=0;i<=npar;i++)
- switch (par[i]) {
+ for (i = 0; i <= vc->vc_npar; i++)
+ switch (vc->vc_par[i]) {
case 0: /* all attributes off */
- default_attr(currcons);
+ default_attr(vc);
break;
case 1:
- intensity = 2;
+ vc->vc_intensity = 2;
break;
case 2:
- intensity = 0;
+ vc->vc_intensity = 0;
break;
case 4:
- underline = 1;
+ vc->vc_underline = 1;
break;
case 5:
- blink = 1;
+ vc->vc_blink = 1;
break;
case 7:
- reverse = 1;
+ vc->vc_reverse = 1;
break;
case 10: /* ANSI X3.64-1979 (SCO-ish?)
* Select primary font, don't display
* control chars if defined, don't set
* bit 8 on output.
*/
- translate = set_translate(charset == 0
- ? G0_charset
- : G1_charset,currcons);
- disp_ctrl = 0;
- toggle_meta = 0;
+ vc->vc_translate = set_translate(vc->vc_charset == 0
+ ? vc->vc_G0_charset
+ : vc->vc_G1_charset, vc);
+ vc->vc_disp_ctrl = 0;
+ vc->vc_toggle_meta = 0;
break;
case 11: /* ANSI X3.64-1979 (SCO-ish?)
* Select first alternate font, lets
* chars < 32 be displayed as ROM chars.
*/
- translate = set_translate(IBMPC_MAP,currcons);
- disp_ctrl = 1;
- toggle_meta = 0;
+ vc->vc_translate = set_translate(IBMPC_MAP, vc);
+ vc->vc_disp_ctrl = 1;
+ vc->vc_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,currcons);
- disp_ctrl = 1;
- toggle_meta = 1;
+ vc->vc_translate = set_translate(IBMPC_MAP, vc);
+ vc->vc_disp_ctrl = 1;
+ vc->vc_toggle_meta = 1;
break;
case 21:
case 22:
- intensity = 1;
+ vc->vc_intensity = 1;
break;
case 24:
- underline = 0;
+ vc->vc_underline = 0;
break;
case 25:
- blink = 0;
+ vc->vc_blink = 0;
break;
case 27:
- reverse = 0;
+ vc->vc_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;
+ vc->vc_color = (vc->vc_def_color & 0x0f) | (vc->vc_color & 0xf0);
+ vc->vc_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;
+ vc->vc_color = (vc->vc_def_color & 0x0f) | (vc->vc_color & 0xf0);
+ vc->vc_underline = 0;
break;
case 49:
- color = (def_color & 0xf0) | foreground;
+ vc->vc_color = (vc->vc_def_color & 0xf0) | (vc->vc_color & 0x0f);
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;
+ if (vc->vc_par[i] >= 30 && vc->vc_par[i] <= 37)
+ vc->vc_color = color_table[vc->vc_par[i] - 30]
+ | (vc->vc_color & 0xf0);
+ else if (vc->vc_par[i] >= 40 && vc->vc_par[i] <= 47)
+ vc->vc_color = (color_table[vc->vc_par[i] - 40] << 4)
+ | (vc->vc_color & 0x0f);
break;
}
- update_attr(currcons);
+ update_attr(vc);
}
static void respond_string(const char *p, struct tty_struct *tty)
con_schedule_flip(tty);
}
-static void cursor_report(int currcons, struct tty_struct *tty)
+static void cursor_report(struct vc_data *vc, struct tty_struct *tty)
{
char buf[40];
- sprintf(buf, "\033[%d;%dR", y + (decom ? top+1 : 1), x+1);
+ sprintf(buf, "\033[%d;%dR", vc->vc_y + (vc->vc_decom ? vc->vc_top + 1 : 1), vc->vc_x + 1);
respond_string(buf, tty);
}
/* invoked via ioctl(TIOCLINUX) and through set_selection */
int mouse_reporting(void)
{
- int currcons = fg_console;
-
- return report_mouse;
+ return vc_cons[fg_console].d->vc_report_mouse;
}
/* console_sem is held */
-static void set_mode(int currcons, int on_off)
+static void set_mode(struct vc_data *vc, int on_off)
{
int i;
- for (i=0; i<=npar; i++)
- if (ques) switch(par[i]) { /* DEC private modes set/reset */
+ for (i = 0; i <= vc->vc_npar; i++)
+ if (vc->vc_ques) {
+ switch(vc->vc_par[i]) { /* DEC private modes set/reset */
case 1: /* Cursor keys send ^[Ox/^[[x */
if (on_off)
- set_kbd(decckm);
+ set_kbd(vc, decckm);
else
- clr_kbd(decckm);
+ clr_kbd(vc, decckm);
break;
case 3: /* 80/132 mode switch unimplemented */
- deccolm = on_off;
+ vc->vc_deccolm = on_off;
#if 0
- (void) vc_resize(deccolm ? 132 : 80, video_num_lines);
+ vc_resize(deccolm ? 132 : 80, vc->vc_rows);
/* this alone does not suffice; some user mode
utility has to change the hardware regs */
#endif
break;
case 5: /* Inverted screen on/off */
- if (decscnm != on_off) {
- decscnm = on_off;
- invert_screen(currcons, 0, screenbuf_size, 0);
- update_attr(currcons);
+ if (vc->vc_decscnm != on_off) {
+ vc->vc_decscnm = on_off;
+ invert_screen(vc, 0, vc->vc_screenbuf_size, 0);
+ update_attr(vc);
}
break;
case 6: /* Origin relative/absolute */
- decom = on_off;
- gotoxay(currcons,0,0);
+ vc->vc_decom = on_off;
+ gotoxay(vc, 0, 0);
break;
case 7: /* Autowrap on/off */
- decawm = on_off;
+ vc->vc_decawm = on_off;
break;
case 8: /* Autorepeat on/off */
if (on_off)
- set_kbd(decarm);
+ set_kbd(vc, decarm);
else
- clr_kbd(decarm);
+ clr_kbd(vc, decarm);
break;
case 9:
- report_mouse = on_off ? 1 : 0;
+ vc->vc_report_mouse = on_off ? 1 : 0;
break;
case 25: /* Cursor on/off */
- deccm = on_off;
+ vc->vc_deccm = on_off;
break;
case 1000:
- report_mouse = on_off ? 2 : 0;
+ vc->vc_report_mouse = on_off ? 2 : 0;
break;
- } else switch(par[i]) { /* ANSI modes set/reset */
+ }
+ } else {
+ switch(vc->vc_par[i]) { /* ANSI modes set/reset */
case 3: /* Monitor (display ctrls) */
- disp_ctrl = on_off;
+ vc->vc_disp_ctrl = on_off;
break;
case 4: /* Insert Mode on/off */
- decim = on_off;
+ vc->vc_decim = on_off;
break;
case 20: /* Lf, Enter == CrLf/Lf */
if (on_off)
- set_kbd(lnm);
+ set_kbd(vc, lnm);
else
- clr_kbd(lnm);
+ clr_kbd(vc, lnm);
break;
+ }
}
}
/* console_sem is held */
-static void setterm_command(int currcons)
+static void setterm_command(struct vc_data *vc)
{
- switch(par[0]) {
+ switch(vc->vc_par[0]) {
case 1: /* set color for underline mode */
- if (can_do_color && par[1] < 16) {
- ulcolor = color_table[par[1]];
- if (underline)
- update_attr(currcons);
+ if (vc->vc_can_do_color &&
+ vc->vc_par[1] < 16) {
+ vc->vc_ulcolor = color_table[vc->vc_par[1]];
+ if (vc->vc_underline)
+ update_attr(vc);
}
break;
case 2: /* set color for half intensity mode */
- if (can_do_color && par[1] < 16) {
- halfcolor = color_table[par[1]];
- if (intensity == 0)
- update_attr(currcons);
+ if (vc->vc_can_do_color &&
+ vc->vc_par[1] < 16) {
+ vc->vc_halfcolor = color_table[vc->vc_par[1]];
+ if (vc->vc_intensity == 0)
+ update_attr(vc);
}
break;
case 8: /* store colors as defaults */
- def_color = attr;
- if (hi_font_mask == 0x100)
- def_color >>= 1;
- default_attr(currcons);
- update_attr(currcons);
+ vc->vc_def_color = vc->vc_attr;
+ if (vc->vc_hi_font_mask == 0x100)
+ vc->vc_def_color >>= 1;
+ default_attr(vc);
+ update_attr(vc);
break;
case 9: /* set blanking interval */
- blankinterval = ((par[1] < 60) ? par[1] : 60) * 60 * HZ;
+ blankinterval = ((vc->vc_par[1] < 60) ? vc->vc_par[1] : 60) * 60 * HZ;
poke_blanked_console();
break;
case 10: /* set bell frequency in Hz */
- if (npar >= 1)
- bell_pitch = par[1];
+ if (vc->vc_npar >= 1)
+ vc->vc_bell_pitch = vc->vc_par[1];
else
- bell_pitch = DEFAULT_BELL_PITCH;
+ vc->vc_bell_pitch = DEFAULT_BELL_PITCH;
break;
case 11: /* set bell duration in msec */
- if (npar >= 1)
- bell_duration = (par[1] < 2000) ?
- par[1]*HZ/1000 : 0;
+ if (vc->vc_npar >= 1)
+ vc->vc_bell_duration = (vc->vc_par[1] < 2000) ?
+ vc->vc_par[1] * HZ / 1000 : 0;
else
- bell_duration = DEFAULT_BELL_DURATION;
+ vc->vc_bell_duration = DEFAULT_BELL_DURATION;
break;
case 12: /* bring specified console to the front */
- if (par[1] >= 1 && vc_cons_allocated(par[1]-1))
- set_console(par[1] - 1);
+ if (vc->vc_par[1] >= 1 && vc_cons_allocated(vc->vc_par[1] - 1))
+ set_console(vc->vc_par[1] - 1);
break;
case 13: /* unblank the screen */
poke_blanked_console();
break;
case 14: /* set vesa powerdown interval */
- vesa_off_interval = ((par[1] < 60) ? par[1] : 60) * 60 * HZ;
+ vesa_off_interval = ((vc->vc_par[1] < 60) ? vc->vc_par[1] : 60) * 60 * HZ;
break;
case 15: /* activate the previous console */
set_console(last_console);
}
/* console_sem is held */
-static void csi_at(int currcons, unsigned int nr)
+static void csi_at(struct vc_data *vc, unsigned int nr)
{
- if (nr > video_num_columns - x)
- nr = video_num_columns - x;
+ if (nr > vc->vc_cols - vc->vc_x)
+ nr = vc->vc_cols - vc->vc_x;
else if (!nr)
nr = 1;
- insert_char(currcons, nr);
+ insert_char(vc, nr);
}
/* console_sem is held */
-static void csi_L(int currcons, unsigned int nr)
+static void csi_L(struct vc_data *vc, unsigned int nr)
{
- if (nr > video_num_lines - y)
- nr = video_num_lines - y;
+ if (nr > vc->vc_rows - vc->vc_y)
+ nr = vc->vc_rows - vc->vc_y;
else if (!nr)
nr = 1;
- scrdown(currcons,y,bottom,nr);
- need_wrap = 0;
+ scrdown(vc, vc->vc_y, vc->vc_bottom, nr);
+ vc->vc_need_wrap = 0;
}
/* console_sem is held */
-static void csi_P(int currcons, unsigned int nr)
+static void csi_P(struct vc_data *vc, unsigned int nr)
{
- if (nr > video_num_columns - x)
- nr = video_num_columns - x;
+ if (nr > vc->vc_cols - vc->vc_x)
+ nr = vc->vc_cols - vc->vc_x;
else if (!nr)
nr = 1;
- delete_char(currcons, nr);
+ delete_char(vc, nr);
}
/* console_sem is held */
-static void csi_M(int currcons, unsigned int nr)
+static void csi_M(struct vc_data *vc, unsigned int nr)
{
- if (nr > video_num_lines - y)
- nr = video_num_lines - y;
+ if (nr > vc->vc_rows - vc->vc_y)
+ nr = vc->vc_rows - vc->vc_y;
else if (!nr)
nr=1;
- scrup(currcons,y,bottom,nr);
- need_wrap = 0;
+ scrup(vc, vc->vc_y, vc->vc_bottom, nr);
+ vc->vc_need_wrap = 0;
}
/* console_sem is held (except via vc_init->reset_terminal */
-static void save_cur(int currcons)
+static void save_cur(struct vc_data *vc)
{
- saved_x = x;
- saved_y = y;
- s_intensity = intensity;
- s_underline = underline;
- s_blink = blink;
- s_reverse = reverse;
- s_charset = charset;
- s_color = color;
- saved_G0 = G0_charset;
- saved_G1 = G1_charset;
+ vc->vc_saved_x = vc->vc_x;
+ vc->vc_saved_y = vc->vc_y;
+ vc->vc_s_intensity = vc->vc_intensity;
+ vc->vc_s_underline = vc->vc_underline;
+ vc->vc_s_blink = vc->vc_blink;
+ vc->vc_s_reverse = vc->vc_reverse;
+ vc->vc_s_charset = vc->vc_charset;
+ vc->vc_s_color = vc->vc_color;
+ vc->vc_saved_G0 = vc->vc_G0_charset;
+ vc->vc_saved_G1 = vc->vc_G1_charset;
}
/* console_sem is held */
-static void restore_cur(int currcons)
-{
- gotoxy(currcons,saved_x,saved_y);
- intensity = s_intensity;
- underline = s_underline;
- blink = s_blink;
- reverse = s_reverse;
- charset = s_charset;
- color = s_color;
- G0_charset = saved_G0;
- G1_charset = saved_G1;
- translate = set_translate(charset ? G1_charset : G0_charset,currcons);
- update_attr(currcons);
- need_wrap = 0;
+static void restore_cur(struct vc_data *vc)
+{
+ gotoxy(vc, vc->vc_saved_x, vc->vc_saved_y);
+ vc->vc_intensity = vc->vc_s_intensity;
+ vc->vc_underline = vc->vc_s_underline;
+ vc->vc_blink = vc->vc_s_blink;
+ vc->vc_reverse = vc->vc_s_reverse;
+ vc->vc_charset = vc->vc_s_charset;
+ vc->vc_color = vc->vc_s_color;
+ vc->vc_G0_charset = vc->vc_saved_G0;
+ vc->vc_G1_charset = vc->vc_saved_G1;
+ vc->vc_translate = set_translate(vc->vc_charset ? vc->vc_G1_charset : vc->vc_G0_charset, vc);
+ update_attr(vc);
+ vc->vc_need_wrap = 0;
}
enum { ESnormal, ESesc, ESsquare, ESgetpars, ESgotpars, ESfunckey,
ESpalette };
/* console_sem is held (except via vc_init()) */
-static void reset_terminal(int currcons, int do_clear)
-{
- top = 0;
- bottom = video_num_lines;
- vc_state = ESnormal;
- ques = 0;
- translate = set_translate(LAT1_MAP,currcons);
- G0_charset = LAT1_MAP;
- G1_charset = GRAF_MAP;
- charset = 0;
- need_wrap = 0;
- report_mouse = 0;
- utf = 0;
- utf_count = 0;
-
- disp_ctrl = 0;
- toggle_meta = 0;
-
- decscnm = 0;
- decom = 0;
- decawm = 1;
- deccm = 1;
- decim = 0;
-
- set_kbd(decarm);
- clr_kbd(decckm);
- clr_kbd(kbdapplic);
- clr_kbd(lnm);
- kbd_table[currcons].lockstate = 0;
- kbd_table[currcons].slockstate = 0;
- kbd_table[currcons].ledmode = LED_SHOW_FLAGS;
- kbd_table[currcons].ledflagstate = kbd_table[currcons].default_ledflagstate;
+static void reset_terminal(struct vc_data *vc, int do_clear)
+{
+ vc->vc_top = 0;
+ vc->vc_bottom = vc->vc_rows;
+ vc->vc_state = ESnormal;
+ vc->vc_ques = 0;
+ vc->vc_translate = set_translate(LAT1_MAP, vc);
+ vc->vc_G0_charset = LAT1_MAP;
+ vc->vc_G1_charset = GRAF_MAP;
+ vc->vc_charset = 0;
+ vc->vc_need_wrap = 0;
+ vc->vc_report_mouse = 0;
+ vc->vc_utf = 1;
+ vc->vc_utf_count = 0;
+
+ vc->vc_disp_ctrl = 0;
+ vc->vc_toggle_meta = 0;
+
+ vc->vc_decscnm = 0;
+ vc->vc_decom = 0;
+ vc->vc_decawm = 1;
+ vc->vc_deccm = 1;
+ vc->vc_decim = 0;
+
+ set_kbd(vc, decarm);
+ clr_kbd(vc, decckm);
+ clr_kbd(vc, kbdapplic);
+ clr_kbd(vc, lnm);
+ kbd_table[vc->vc_num].lockstate = 0;
+ kbd_table[vc->vc_num].slockstate = 0;
+ kbd_table[vc->vc_num].ledmode = LED_SHOW_FLAGS;
+ kbd_table[vc->vc_num].ledflagstate = kbd_table[vc->vc_num].default_ledflagstate;
/* do not do set_leds here because this causes an endless tasklet loop
when the keyboard hasn't been initialized yet */
- cursor_type = CUR_DEFAULT;
- complement_mask = s_complement_mask;
+ vc->vc_cursor_type = CUR_DEFAULT;
+ vc->vc_complement_mask = vc->vc_s_complement_mask;
- default_attr(currcons);
- update_attr(currcons);
+ default_attr(vc);
+ update_attr(vc);
- tab_stop[0] = 0x01010100;
- tab_stop[1] =
- tab_stop[2] =
- tab_stop[3] =
- tab_stop[4] = 0x01010101;
+ vc->vc_tab_stop[0] = 0x01010100;
+ vc->vc_tab_stop[1] =
+ vc->vc_tab_stop[2] =
+ vc->vc_tab_stop[3] =
+ vc->vc_tab_stop[4] = 0x01010101;
- bell_pitch = DEFAULT_BELL_PITCH;
- bell_duration = DEFAULT_BELL_DURATION;
+ vc->vc_bell_pitch = DEFAULT_BELL_PITCH;
+ vc->vc_bell_duration = DEFAULT_BELL_DURATION;
- gotoxy(currcons,0,0);
- save_cur(currcons);
+ gotoxy(vc, 0, 0);
+ save_cur(vc);
if (do_clear)
- csi_J(currcons,2);
+ csi_J(vc, 2);
}
/* console_sem is held */
-static void do_con_trol(struct tty_struct *tty, unsigned int currcons, int c)
+static void do_con_trol(struct tty_struct *tty, struct vc_data *vc, int c)
{
/*
* Control characters can be used in the _middle_
case 0:
return;
case 7:
- if (bell_duration)
- kd_mksound(bell_pitch, bell_duration);
+ if (vc->vc_bell_duration)
+ kd_mksound(vc->vc_bell_pitch, vc->vc_bell_duration);
return;
case 8:
- bs(currcons);
+ bs(vc);
return;
case 9:
- pos -= (x << 1);
- while (x < video_num_columns - 1) {
- x++;
- if (tab_stop[x >> 5] & (1 << (x & 31)))
+ vc->vc_pos -= (vc->vc_x << 1);
+ while (vc->vc_x < vc->vc_cols - 1) {
+ vc->vc_x++;
+ if (vc->vc_tab_stop[vc->vc_x >> 5] & (1 << (vc->vc_x & 31)))
break;
}
- pos += (x << 1);
+ vc->vc_pos += (vc->vc_x << 1);
return;
case 10: case 11: case 12:
- lf(currcons);
- if (!is_kbd(lnm))
+ lf(vc);
+ if (!is_kbd(vc, lnm))
return;
case 13:
- cr(currcons);
+ cr(vc);
return;
case 14:
- charset = 1;
- translate = set_translate(G1_charset,currcons);
- disp_ctrl = 1;
+ vc->vc_charset = 1;
+ vc->vc_translate = set_translate(vc->vc_G1_charset, vc);
+ vc->vc_disp_ctrl = 1;
return;
case 15:
- charset = 0;
- translate = set_translate(G0_charset,currcons);
- disp_ctrl = 0;
+ vc->vc_charset = 0;
+ vc->vc_translate = set_translate(vc->vc_G0_charset, vc);
+ vc->vc_disp_ctrl = 0;
return;
case 24: case 26:
- vc_state = ESnormal;
+ vc->vc_state = ESnormal;
return;
case 27:
- vc_state = ESesc;
+ vc->vc_state = ESesc;
return;
case 127:
- del(currcons);
+ del(vc);
return;
case 128+27:
- vc_state = ESsquare;
+ vc->vc_state = ESsquare;
return;
}
- switch(vc_state) {
+ switch(vc->vc_state) {
case ESesc:
- vc_state = ESnormal;
+ vc->vc_state = ESnormal;
switch (c) {
case '[':
- vc_state = ESsquare;
+ vc->vc_state = ESsquare;
return;
case ']':
- vc_state = ESnonstd;
+ vc->vc_state = ESnonstd;
return;
case '%':
- vc_state = ESpercent;
+ vc->vc_state = ESpercent;
return;
case 'E':
- cr(currcons);
- lf(currcons);
+ cr(vc);
+ lf(vc);
return;
case 'M':
- ri(currcons);
+ ri(vc);
return;
case 'D':
- lf(currcons);
+ lf(vc);
return;
case 'H':
- tab_stop[x >> 5] |= (1 << (x & 31));
+ vc->vc_tab_stop[vc->vc_x >> 5] |= (1 << (vc->vc_x & 31));
return;
case 'Z':
respond_ID(tty);
return;
case '7':
- save_cur(currcons);
+ save_cur(vc);
return;
case '8':
- restore_cur(currcons);
+ restore_cur(vc);
return;
case '(':
- vc_state = ESsetG0;
+ vc->vc_state = ESsetG0;
return;
case ')':
- vc_state = ESsetG1;
+ vc->vc_state = ESsetG1;
return;
case '#':
- vc_state = EShash;
+ vc->vc_state = EShash;
return;
case 'c':
- reset_terminal(currcons,1);
+ reset_terminal(vc, 1);
return;
case '>': /* Numeric keypad */
- clr_kbd(kbdapplic);
+ clr_kbd(vc, kbdapplic);
return;
case '=': /* Appl. keypad */
- set_kbd(kbdapplic);
+ set_kbd(vc, 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;
+ for (vc->vc_npar = 0; vc->vc_npar < NPAR; vc->vc_npar++)
+ vc->vc_par[vc->vc_npar] = 0;
+ vc->vc_npar = 0;
+ vc->vc_state = ESpalette;
return;
} else if (c=='R') { /* reset palette */
- reset_palette(currcons);
- vc_state = ESnormal;
+ reset_palette(vc);
+ vc->vc_state = ESnormal;
} else
- vc_state = ESnormal;
+ vc->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(currcons);
- vc_state = ESnormal;
+ vc->vc_par[vc->vc_npar++] = (c > '9' ? (c & 0xDF) - 'A' + 10 : c - '0');
+ if (vc->vc_npar == 7) {
+ int i = vc->vc_par[0] * 3, j = 1;
+ vc->vc_palette[i] = 16 * vc->vc_par[j++];
+ vc->vc_palette[i++] += vc->vc_par[j++];
+ vc->vc_palette[i] = 16 * vc->vc_par[j++];
+ vc->vc_palette[i++] += vc->vc_par[j++];
+ vc->vc_palette[i] = 16 * vc->vc_par[j++];
+ vc->vc_palette[i] += vc->vc_par[j];
+ set_palette(vc);
+ vc->vc_state = ESnormal;
}
} else
- vc_state = ESnormal;
+ vc->vc_state = ESnormal;
return;
case ESsquare:
- for(npar = 0 ; npar < NPAR ; npar++)
- par[npar] = 0;
- npar = 0;
- vc_state = ESgetpars;
+ for (vc->vc_npar = 0; vc->vc_npar < NPAR; vc->vc_npar++)
+ vc->vc_par[vc->vc_npar] = 0;
+ vc->vc_npar = 0;
+ vc->vc_state = ESgetpars;
if (c == '[') { /* Function key */
- vc_state=ESfunckey;
+ vc->vc_state=ESfunckey;
return;
}
- ques = (c=='?');
- if (ques)
+ vc->vc_ques = (c == '?');
+ if (vc->vc_ques)
return;
case ESgetpars:
- if (c==';' && npar<NPAR-1) {
- npar++;
+ if (c == ';' && vc->vc_npar < NPAR - 1) {
+ vc->vc_npar++;
return;
} else if (c>='0' && c<='9') {
- par[npar] *= 10;
- par[npar] += c-'0';
+ vc->vc_par[vc->vc_npar] *= 10;
+ vc->vc_par[vc->vc_npar] += c - '0';
return;
- } else vc_state=ESgotpars;
+ } else
+ vc->vc_state = ESgotpars;
case ESgotpars:
- vc_state = ESnormal;
+ vc->vc_state = ESnormal;
switch(c) {
case 'h':
- set_mode(currcons,1);
+ set_mode(vc, 1);
return;
case 'l':
- set_mode(currcons,0);
+ set_mode(vc, 0);
return;
case 'c':
- if (ques) {
- if (par[0])
- cursor_type = par[0] | (par[1]<<8) | (par[2]<<16);
+ if (vc->vc_ques) {
+ if (vc->vc_par[0])
+ vc->vc_cursor_type = vc->vc_par[0] | (vc->vc_par[1] << 8) | (vc->vc_par[2] << 16);
else
- cursor_type = CUR_DEFAULT;
+ vc->vc_cursor_type = CUR_DEFAULT;
return;
}
break;
case 'm':
- if (ques) {
+ if (vc->vc_ques) {
clear_selection();
- if (par[0])
- complement_mask = par[0]<<8 | par[1];
+ if (vc->vc_par[0])
+ vc->vc_complement_mask = vc->vc_par[0] << 8 | vc->vc_par[1];
else
- complement_mask = s_complement_mask;
+ vc->vc_complement_mask = vc->vc_s_complement_mask;
return;
}
break;
case 'n':
- if (!ques) {
- if (par[0] == 5)
+ if (!vc->vc_ques) {
+ if (vc->vc_par[0] == 5)
status_report(tty);
- else if (par[0] == 6)
- cursor_report(currcons,tty);
+ else if (vc->vc_par[0] == 6)
+ cursor_report(vc, tty);
}
return;
}
- if (ques) {
- ques = 0;
+ if (vc->vc_ques) {
+ vc->vc_ques = 0;
return;
}
switch(c) {
case 'G': case '`':
- if (par[0]) par[0]--;
- gotoxy(currcons,par[0],y);
+ if (vc->vc_par[0])
+ vc->vc_par[0]--;
+ gotoxy(vc, vc->vc_par[0], vc->vc_y);
return;
case 'A':
- if (!par[0]) par[0]++;
- gotoxy(currcons,x,y-par[0]);
+ if (!vc->vc_par[0])
+ vc->vc_par[0]++;
+ gotoxy(vc, vc->vc_x, vc->vc_y - vc->vc_par[0]);
return;
case 'B': case 'e':
- if (!par[0]) par[0]++;
- gotoxy(currcons,x,y+par[0]);
+ if (!vc->vc_par[0])
+ vc->vc_par[0]++;
+ gotoxy(vc, vc->vc_x, vc->vc_y + vc->vc_par[0]);
return;
case 'C': case 'a':
- if (!par[0]) par[0]++;
- gotoxy(currcons,x+par[0],y);
+ if (!vc->vc_par[0])
+ vc->vc_par[0]++;
+ gotoxy(vc, vc->vc_x + vc->vc_par[0], vc->vc_y);
return;
case 'D':
- if (!par[0]) par[0]++;
- gotoxy(currcons,x-par[0],y);
+ if (!vc->vc_par[0])
+ vc->vc_par[0]++;
+ gotoxy(vc, vc->vc_x - vc->vc_par[0], vc->vc_y);
return;
case 'E':
- if (!par[0]) par[0]++;
- gotoxy(currcons,0,y+par[0]);
+ if (!vc->vc_par[0])
+ vc->vc_par[0]++;
+ gotoxy(vc, 0, vc->vc_y + vc->vc_par[0]);
return;
case 'F':
- if (!par[0]) par[0]++;
- gotoxy(currcons,0,y-par[0]);
+ if (!vc->vc_par[0])
+ vc->vc_par[0]++;
+ gotoxy(vc, 0, vc->vc_y - vc->vc_par[0]);
return;
case 'd':
- if (par[0]) par[0]--;
- gotoxay(currcons,x,par[0]);
+ if (vc->vc_par[0])
+ vc->vc_par[0]--;
+ gotoxay(vc, vc->vc_x ,vc->vc_par[0]);
return;
case 'H': case 'f':
- if (par[0]) par[0]--;
- if (par[1]) par[1]--;
- gotoxay(currcons,par[1],par[0]);
+ if (vc->vc_par[0])
+ vc->vc_par[0]--;
+ if (vc->vc_par[1])
+ vc->vc_par[1]--;
+ gotoxay(vc, vc->vc_par[1], vc->vc_par[0]);
return;
case 'J':
- csi_J(currcons,par[0]);
+ csi_J(vc, vc->vc_par[0]);
return;
case 'K':
- csi_K(currcons,par[0]);
+ csi_K(vc, vc->vc_par[0]);
return;
case 'L':
- csi_L(currcons,par[0]);
+ csi_L(vc, vc->vc_par[0]);
return;
case 'M':
- csi_M(currcons,par[0]);
+ csi_M(vc, vc->vc_par[0]);
return;
case 'P':
- csi_P(currcons,par[0]);
+ csi_P(vc, vc->vc_par[0]);
return;
case 'c':
- if (!par[0])
+ if (!vc->vc_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;
+ if (!vc->vc_par[0])
+ vc->vc_tab_stop[vc->vc_x >> 5] &= ~(1 << (vc->vc_x & 31));
+ else if (vc->vc_par[0] == 3) {
+ vc->vc_tab_stop[0] =
+ vc->vc_tab_stop[1] =
+ vc->vc_tab_stop[2] =
+ vc->vc_tab_stop[3] =
+ vc->vc_tab_stop[4] = 0;
}
return;
case 'm':
- csi_m(currcons);
+ csi_m(vc);
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);
+ if (vc->vc_par[0] < 4)
+ setledstate(kbd_table + vc->vc_num,
+ (vc->vc_par[0] < 3) ? vc->vc_par[0] : 4);
return;
case 'r':
- if (!par[0])
- par[0]++;
- if (!par[1])
- par[1] = video_num_lines;
+ if (!vc->vc_par[0])
+ vc->vc_par[0]++;
+ if (!vc->vc_par[1])
+ vc->vc_par[1] = vc->vc_rows;
/* 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);
+ if (vc->vc_par[0] < vc->vc_par[1] &&
+ vc->vc_par[1] <= vc->vc_rows) {
+ vc->vc_top = vc->vc_par[0] - 1;
+ vc->vc_bottom = vc->vc_par[1];
+ gotoxay(vc, 0, 0);
}
return;
case 's':
- save_cur(currcons);
+ save_cur(vc);
return;
case 'u':
- restore_cur(currcons);
+ restore_cur(vc);
return;
case 'X':
- csi_X(currcons, par[0]);
+ csi_X(vc, vc->vc_par[0]);
return;
case '@':
- csi_at(currcons,par[0]);
+ csi_at(vc, vc->vc_par[0]);
return;
case ']': /* setterm functions */
- setterm_command(currcons);
+ setterm_command(vc);
return;
}
return;
case ESpercent:
- vc_state = ESnormal;
+ vc->vc_state = ESnormal;
switch (c) {
case '@': /* defined in ISO 2022 */
- utf = 0;
+ vc->vc_utf = 0;
return;
case 'G': /* prelim official escape code */
case '8': /* retained for compatibility */
- utf = 1;
+ vc->vc_utf = 1;
return;
}
return;
case ESfunckey:
- vc_state = ESnormal;
+ vc->vc_state = ESnormal;
return;
case EShash:
- vc_state = ESnormal;
+ vc->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);
+ vc->vc_video_erase_char =
+ (vc->vc_video_erase_char & 0xff00) | 'E';
+ csi_J(vc, 2);
+ vc->vc_video_erase_char =
+ (vc->vc_video_erase_char & 0xff00) | ' ';
+ do_update_region(vc, vc->vc_origin, vc->vc_screenbuf_size / 2);
}
return;
case ESsetG0:
if (c == '0')
- G0_charset = GRAF_MAP;
+ vc->vc_G0_charset = GRAF_MAP;
else if (c == 'B')
- G0_charset = LAT1_MAP;
+ vc->vc_G0_charset = LAT1_MAP;
else if (c == 'U')
- G0_charset = IBMPC_MAP;
+ vc->vc_G0_charset = IBMPC_MAP;
else if (c == 'K')
- G0_charset = USER_MAP;
- if (charset == 0)
- translate = set_translate(G0_charset,currcons);
- vc_state = ESnormal;
+ vc->vc_G0_charset = USER_MAP;
+ if (vc->vc_charset == 0)
+ vc->vc_translate = set_translate(vc->vc_G0_charset, vc);
+ vc->vc_state = ESnormal;
return;
case ESsetG1:
if (c == '0')
- G1_charset = GRAF_MAP;
+ vc->vc_G1_charset = GRAF_MAP;
else if (c == 'B')
- G1_charset = LAT1_MAP;
+ vc->vc_G1_charset = LAT1_MAP;
else if (c == 'U')
- G1_charset = IBMPC_MAP;
+ vc->vc_G1_charset = IBMPC_MAP;
else if (c == 'K')
- G1_charset = USER_MAP;
- if (charset == 1)
- translate = set_translate(G1_charset,currcons);
- vc_state = ESnormal;
+ vc->vc_G1_charset = USER_MAP;
+ if (vc->vc_charset == 1)
+ vc->vc_translate = set_translate(vc->vc_G1_charset, vc);
+ vc->vc_state = ESnormal;
return;
default:
- vc_state = ESnormal;
+ vc->vc_state = ESnormal;
}
}
* since console_init (and thus con_init) are called before any
* kernel memory allocation is available.
*/
-char con_buf[PAGE_SIZE];
+char con_buf[CON_BUF_SIZE];
DECLARE_MUTEX(con_buf_sem);
/* acquires console_sem */
-static int do_con_write(struct tty_struct *tty, int from_user,
- const unsigned char *buf, int count)
+static int do_con_write(struct tty_struct *tty, const unsigned char *buf, int count)
{
#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); \
+ vc->vc_sw->con_putcs(vc, (u16 *)draw_from, (u16 *)draw_to - (u16 *)draw_from, vc->vc_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 vc_data *vc;
u16 himask, charmask;
const unsigned char *orig_buf = NULL;
int orig_count;
might_sleep();
acquire_console_sem();
- vt = tty->driver_data;
- if (vt == NULL) {
+ vc = tty->driver_data;
+ if (vc == NULL) {
printk(KERN_ERR "vt: argh, driver_data is NULL !\n");
release_console_sem();
return 0;
}
- currcons = vt->vc_num;
+ currcons = vc->vc_num;
if (!vc_cons_allocated(currcons)) {
/* could this happen? */
static int error = 0;
orig_buf = buf;
orig_count = count;
- if (from_user) {
-
- down(&con_buf_sem);
-
-again:
- if (count > CON_BUF_SIZE)
- count = CON_BUF_SIZE;
- console_conditional_schedule();
- if (copy_from_user(con_buf, buf, count)) {
- n = 0; /* ?? are error codes legal here ?? */
- goto out;
- }
-
- buf = con_buf;
- }
-
/* At this point 'buf' is guaranteed to be a kernel buffer
* and therefore no access to userspace (and therefore sleeping)
* will be needed. The con_buf_sem serializes all tty based
acquire_console_sem();
- vt = tty->driver_data;
- if (vt == NULL) {
+ vc = tty->driver_data;
+ if (vc == NULL) {
printk(KERN_ERR "vt: argh, driver_data _became_ NULL !\n");
release_console_sem();
goto out;
}
- himask = hi_font_mask;
+ himask = vc->vc_hi_font_mask;
charmask = himask ? 0x1ff : 0xff;
/* undraw cursor first */
- if (IS_FG)
- hide_cursor(currcons);
+ if (IS_FG(vc))
+ hide_cursor(vc);
while (!tty->stopped && count) {
- c = *buf;
+ int orig = *buf;
+ c = orig;
buf++;
n++;
count--;
- if (utf) {
+ /* Do no translation at all in control states */
+ if (vc->vc_state != ESnormal) {
+ tc = c;
+ } else if (vc->vc_utf && !vc->vc_disp_ctrl) {
/* Combine UTF-8 into Unicode */
- /* Incomplete characters silently ignored */
+ /* Malformed sequences as sequences of replacement glyphs */
+rescan_last_byte:
if(c > 0x7f) {
- if (utf_count > 0 && (c & 0xc0) == 0x80) {
- utf_char = (utf_char << 6) | (c & 0x3f);
- utf_count--;
- if (utf_count == 0)
- tc = c = utf_char;
- else continue;
+ if (vc->vc_utf_count) {
+ if ((c & 0xc0) == 0x80) {
+ vc->vc_utf_char = (vc->vc_utf_char << 6) | (c & 0x3f);
+ if (--vc->vc_utf_count) {
+ vc->vc_npar++;
+ continue;
+ }
+ tc = c = vc->vc_utf_char;
+ } else
+ goto replacement_glyph;
} else {
+ vc->vc_npar = 0;
if ((c & 0xe0) == 0xc0) {
- utf_count = 1;
- utf_char = (c & 0x1f);
+ vc->vc_utf_count = 1;
+ vc->vc_utf_char = (c & 0x1f);
} else if ((c & 0xf0) == 0xe0) {
- utf_count = 2;
- utf_char = (c & 0x0f);
+ vc->vc_utf_count = 2;
+ vc->vc_utf_char = (c & 0x0f);
} else if ((c & 0xf8) == 0xf0) {
- utf_count = 3;
- utf_char = (c & 0x07);
+ vc->vc_utf_count = 3;
+ vc->vc_utf_char = (c & 0x07);
} else if ((c & 0xfc) == 0xf8) {
- utf_count = 4;
- utf_char = (c & 0x03);
+ vc->vc_utf_count = 4;
+ vc->vc_utf_char = (c & 0x03);
} else if ((c & 0xfe) == 0xfc) {
- utf_count = 5;
- utf_char = (c & 0x01);
+ vc->vc_utf_count = 5;
+ vc->vc_utf_char = (c & 0x01);
} else
- utf_count = 0;
+ goto replacement_glyph;
continue;
}
} else {
+ if (vc->vc_utf_count)
+ goto replacement_glyph;
tc = c;
- utf_count = 0;
}
- } else { /* no utf */
- tc = translate[toggle_meta ? (c|0x80) : c];
+ } else { /* no utf or alternate charset mode */
+ tc = vc->vc_translate[vc->vc_toggle_meta ? (c | 0x80) : c];
}
/* If the original code was a control character we
* direct-to-font zone in UTF-8 mode.
*/
ok = tc && (c >= 32 ||
- (!utf && !(((disp_ctrl ? CTRL_ALWAYS
- : CTRL_ACTION) >> c) & 1)))
- && (c != 127 || disp_ctrl)
+ !(vc->vc_disp_ctrl ? (CTRL_ALWAYS >> c) & 1 :
+ vc->vc_utf || ((CTRL_ACTION >> c) & 1)))
+ && (c != 127 || vc->vc_disp_ctrl)
&& (c != 128+27);
- if (vc_state == ESnormal && ok) {
+ if (vc->vc_state == ESnormal && ok) {
/* Now try to find out how to display it */
- tc = conv_uni_to_pc(vc_cons[currcons].d, tc);
- if ( tc == -4 ) {
+ tc = conv_uni_to_pc(vc, tc);
+ if (tc & ~charmask) {
+ 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(vc_cons[currcons].d, 0xfffd);
-
- /* One reason for the -4 can be that we just
- did a clear_unimap();
- try at least to show something. */
- if (tc == -4)
- tc = c;
- } else if ( tc == -3 ) {
- /* Bad hash table -- hope for the best */
- tc = c;
- }
- if (tc & ~charmask)
- continue; /* Conversion failed */
-
- if (need_wrap || decim)
+replacement_glyph:
+ tc = conv_uni_to_pc(vc, 0xfffd);
+ if (!(tc & ~charmask))
+ goto display_glyph;
+ } else if ( tc != -3 )
+ continue; /* nothing to display */
+ /* no hash table or no replacement --
+ * hope for the best */
+ if ( c & ~charmask )
+ tc = '?';
+ else
+ tc = c;
+ }
+
+display_glyph:
+ if (vc->vc_need_wrap || vc->vc_decim)
FLUSH
- if (need_wrap) {
- cr(currcons);
- lf(currcons);
+ if (vc->vc_need_wrap) {
+ cr(vc);
+ lf(vc);
}
- if (decim)
- insert_char(currcons, 1);
+ if (vc->vc_decim)
+ insert_char(vc, 1);
scr_writew(himask ?
- ((attr << 8) & ~himask) + ((tc & 0x100) ? himask : 0) + (tc & 0xff) :
- (attr << 8) + tc,
- (u16 *) pos);
- if (DO_UPDATE && draw_x < 0) {
- draw_x = x;
- draw_from = pos;
+ ((vc->vc_attr << 8) & ~himask) + ((tc & 0x100) ? himask : 0) + (tc & 0xff) :
+ (vc->vc_attr << 8) + tc,
+ (u16 *) vc->vc_pos);
+ if (DO_UPDATE(vc) && draw_x < 0) {
+ draw_x = vc->vc_x;
+ draw_from = vc->vc_pos;
}
- if (x == video_num_columns - 1) {
- need_wrap = decawm;
- draw_to = pos+2;
+ if (vc->vc_x == vc->vc_cols - 1) {
+ vc->vc_need_wrap = vc->vc_decawm;
+ draw_to = vc->vc_pos + 2;
} else {
- x++;
- draw_to = (pos+=2);
+ vc->vc_x++;
+ draw_to = (vc->vc_pos += 2);
+ }
+ if (vc->vc_utf_count) {
+ if (vc->vc_npar) {
+ vc->vc_npar--;
+ goto display_glyph;
+ }
+ vc->vc_utf_count = 0;
+ c = orig;
+ goto rescan_last_byte;
}
continue;
}
FLUSH
- do_con_trol(tty, currcons, c);
+ do_con_trol(tty, vc, orig);
}
FLUSH
console_conditional_schedule();
release_console_sem();
out:
- if (from_user) {
- /* If the user requested something larger than
- * the CON_BUF_SIZE, and the tty is not stopped,
- * keep going.
- */
- if ((orig_count > CON_BUF_SIZE) && !tty->stopped) {
- orig_count -= CON_BUF_SIZE;
- orig_buf += CON_BUF_SIZE;
- count = orig_count;
- buf = orig_buf;
- goto again;
- }
-
- up(&con_buf_sem);
- }
-
return n;
#undef FLUSH
}
* with other console code and prevention of re-entrancy is
* ensured with console_sem.
*/
-static void console_callback(void *ignored)
+static void console_callback(struct work_struct *ignored)
{
acquire_console_sem();
if (want_console >= 0) {
if (want_console != fg_console &&
vc_cons_allocated(want_console)) {
- hide_cursor(fg_console);
- change_console(want_console);
+ hide_cursor(vc_cons[fg_console].d);
+ change_console(vc_cons[want_console].d);
/* we only changed when the console had already
been allocated - a new console is not created
in an interrupt routine */
poke_blanked_console();
}
if (scrollback_delta) {
- int currcons = fg_console;
+ struct vc_data *vc = vc_cons[fg_console].d;
clear_selection();
- if (vcmode == KD_TEXT)
- sw->con_scrolldelta(vc_cons[currcons].d, scrollback_delta);
+ if (vc->vc_mode == KD_TEXT)
+ vc->vc_sw->con_scrolldelta(vc, scrollback_delta);
scrollback_delta = 0;
}
if (blank_timer_expired) {
* The console must be locked when we get here.
*/
-void vt_console_print(struct console *co, const char *b, unsigned count)
+static void vt_console_print(struct console *co, const char *b, unsigned count)
{
- int currcons = fg_console;
+ struct vc_data *vc = vc_cons[fg_console].d;
unsigned char c;
static unsigned long printing;
const ushort *start;
if (!printable || test_and_set_bit(0, &printing))
return;
- pm_access(pm_con);
-
if (kmsg_redirect && vc_cons_allocated(kmsg_redirect - 1))
- currcons = kmsg_redirect - 1;
+ vc = vc_cons[kmsg_redirect - 1].d;
/* read `x' only after setting currcons properly (otherwise
the `x' macro will read the x of the foreground console). */
- myx = x;
+ myx = vc->vc_x;
- if (!vc_cons_allocated(currcons)) {
+ if (!vc_cons_allocated(fg_console)) {
/* impossible */
/* printk("vt_console_print: tty %d not allocated ??\n", currcons+1); */
goto quit;
}
- if (vcmode != KD_TEXT)
+ if (vc->vc_mode != KD_TEXT)
goto quit;
/* undraw cursor first */
- if (IS_FG)
- hide_cursor(currcons);
+ if (IS_FG(vc))
+ hide_cursor(vc);
- start = (ushort *)pos;
+ start = (ushort *)vc->vc_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 (c == 10 || c == 13 || c == 8 || vc->vc_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--;
+ if (CON_IS_VISIBLE(vc))
+ vc->vc_sw->con_putcs(vc, start, cnt, vc->vc_y, vc->vc_x);
+ vc->vc_x += cnt;
+ if (vc->vc_need_wrap)
+ vc->vc_x--;
cnt = 0;
}
if (c == 8) { /* backspace */
- bs(currcons);
- start = (ushort *)pos;
- myx = x;
+ bs(vc);
+ start = (ushort *)vc->vc_pos;
+ myx = vc->vc_x;
continue;
}
if (c != 13)
- lf(currcons);
- cr(currcons);
- start = (ushort *)pos;
- myx = x;
+ lf(vc);
+ cr(vc);
+ start = (ushort *)vc->vc_pos;
+ myx = vc->vc_x;
if (c == 10 || c == 13)
continue;
}
- scr_writew((attr << 8) + c, (unsigned short *) pos);
+ scr_writew((vc->vc_attr << 8) + c, (unsigned short *)vc->vc_pos);
cnt++;
- if (myx == video_num_columns - 1) {
- need_wrap = 1;
+ if (myx == vc->vc_cols - 1) {
+ vc->vc_need_wrap = 1;
continue;
}
- pos+=2;
+ vc->vc_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;
+ if (CON_IS_VISIBLE(vc))
+ vc->vc_sw->con_putcs(vc, start, cnt, vc->vc_y, vc->vc_x);
+ vc->vc_x += cnt;
+ if (vc->vc_x == vc->vc_cols) {
+ vc->vc_x--;
+ vc->vc_need_wrap = 1;
}
}
- set_cursor(currcons);
-
- if (!oops_in_progress)
- poke_blanked_console();
+ set_cursor(vc);
quit:
clear_bit(0, &printing);
return console_driver;
}
-struct console vt_console_driver = {
+static struct console vt_console_driver = {
.name = "tty",
.write = vt_console_print,
.device = vt_console_device,
ret = paste_selection(tty);
break;
case TIOCL_UNBLANKSCREEN:
+ acquire_console_sem();
unblank_screen();
+ release_console_sem();
break;
case TIOCL_SELLOADLUT:
ret = sel_loadlut(p);
ret = __put_user(data, p);
break;
case TIOCL_SETVESABLANK:
- set_vesa_blanking(p);
+ ret = set_vesa_blanking(p);
+ break;
+ case TIOCL_GETKMSGREDIRECT:
+ data = kmsg_redirect;
+ ret = __put_user(data, p);
break;
case TIOCL_SETKMSGREDIRECT:
if (!capable(CAP_SYS_ADMIN)) {
if (get_user(lines, (s32 __user *)(p+4))) {
ret = -EFAULT;
} else {
- scrollfront(lines);
+ scrollfront(vc_cons[fg_console].d, lines);
ret = 0;
}
break;
case TIOCL_BLANKSCREEN: /* until explicitly unblanked, not only poked */
+ acquire_console_sem();
ignore_poke = 1;
do_blank_screen(0);
+ release_console_sem();
break;
case TIOCL_BLANKEDSCREEN:
ret = console_blanked;
* /dev/ttyN handling
*/
-static int con_write(struct tty_struct *tty, int from_user,
- const unsigned char *buf, int count)
+static int con_write(struct tty_struct *tty, const unsigned char *buf, int count)
{
int retval;
- pm_access(pm_con);
- retval = do_con_write(tty, from_user, buf, count);
+ retval = do_con_write(tty, buf, count);
con_flush_chars(tty);
return retval;
{
if (in_interrupt())
return; /* n_r3964 calls put_char() from interrupt context */
- pm_access(pm_con);
- do_con_write(tty, 0, &ch, 1);
+ do_con_write(tty, &ch, 1);
}
static int con_write_room(struct tty_struct *tty)
static void con_unthrottle(struct tty_struct *tty)
{
- struct vt_struct *vt = tty->driver_data;
+ struct vc_data *vc = tty->driver_data;
- wake_up_interruptible(&vt->paste_wait);
+ wake_up_interruptible(&vc->paste_wait);
}
/*
static void con_flush_chars(struct tty_struct *tty)
{
- struct vt_struct *vt;
+ struct vc_data *vc;
if (in_interrupt()) /* from flush_to_ldisc */
return;
- pm_access(pm_con);
-
/* if we race with con_close(), vt may be null */
acquire_console_sem();
- vt = tty->driver_data;
- if (vt)
- set_cursor(vt->vc_num);
+ vc = tty->driver_data;
+ if (vc)
+ set_cursor(vc);
release_console_sem();
}
int ret = 0;
acquire_console_sem();
- if (tty->count == 1) {
+ if (tty->driver_data == NULL) {
ret = vc_allocate(currcons);
if (ret == 0) {
- vt_cons[currcons]->vc_num = currcons;
- tty->driver_data = vt_cons[currcons];
- vc_cons[currcons].d->vc_tty = tty;
+ struct vc_data *vc = vc_cons[currcons].d;
+ tty->driver_data = vc;
+ vc->vc_tty = tty;
if (!tty->winsize.ws_row && !tty->winsize.ws_col) {
- tty->winsize.ws_row = video_num_lines;
- tty->winsize.ws_col = video_num_columns;
+ tty->winsize.ws_row = vc_cons[currcons].d->vc_rows;
+ tty->winsize.ws_col = vc_cons[currcons].d->vc_cols;
}
release_console_sem();
- vcs_make_devfs(tty);
+ vcs_make_sysfs(tty);
return ret;
}
}
}
/*
- * We take tty_sem in here to prevent another thread from coming in via init_dev
+ * We take tty_mutex in here to prevent another thread from coming in via init_dev
* and taking a ref against the tty while we're in the process of forgetting
* about it and cleaning things up.
*
- * This is because vcs_remove_devfs() can sleep and will drop the BKL.
+ * This is because vcs_remove_sysfs() can sleep and will drop the BKL.
*/
static void con_close(struct tty_struct *tty, struct file *filp)
{
- down(&tty_sem);
+ mutex_lock(&tty_mutex);
acquire_console_sem();
if (tty && tty->count == 1) {
- struct vt_struct *vt;
+ struct vc_data *vc = tty->driver_data;
- vt = tty->driver_data;
- if (vt)
- vc_cons[vt->vc_num].d->vc_tty = NULL;
+ if (vc)
+ vc->vc_tty = NULL;
tty->driver_data = NULL;
release_console_sem();
- vcs_remove_devfs(tty);
- up(&tty_sem);
+ vcs_remove_sysfs(tty);
+ mutex_unlock(&tty_mutex);
/*
- * tty_sem is released, but we still hold BKL, so there is
+ * tty_mutex is released, but we still hold BKL, so there is
* still exclusion against init_dev()
*/
return;
}
release_console_sem();
- up(&tty_sem);
+ mutex_unlock(&tty_mutex);
}
-static void vc_init(unsigned int currcons, unsigned int rows,
- unsigned int cols, int do_clear)
+static void vc_init(struct vc_data *vc, unsigned int rows,
+ unsigned int cols, int do_clear)
{
int j, k ;
- video_num_columns = cols;
- video_num_lines = rows;
- video_size_row = cols<<1;
- screenbuf_size = video_num_lines * video_size_row;
+ vc->vc_cols = cols;
+ vc->vc_rows = rows;
+ vc->vc_size_row = cols << 1;
+ vc->vc_screenbuf_size = vc->vc_rows * vc->vc_size_row;
- set_origin(currcons);
- pos = origin;
- reset_vc(currcons);
+ set_origin(vc);
+ vc->vc_pos = vc->vc_origin;
+ reset_vc(vc);
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] ;
+ vc->vc_palette[k++] = default_red[j] ;
+ vc->vc_palette[k++] = default_grn[j] ;
+ vc->vc_palette[k++] = default_blu[j] ;
}
- def_color = 0x07; /* white */
- ulcolor = 0x0f; /* bold white */
- halfcolor = 0x08; /* grey */
- init_waitqueue_head(&vt_cons[currcons]->paste_wait);
- reset_terminal(currcons, do_clear);
+ vc->vc_def_color = 0x07; /* white */
+ vc->vc_ulcolor = 0x0f; /* bold white */
+ vc->vc_halfcolor = 0x08; /* grey */
+ init_waitqueue_head(&vc->paste_wait);
+ reset_terminal(vc, do_clear);
}
/*
static int __init con_init(void)
{
const char *display_desc = NULL;
- unsigned int currcons = 0;
+ struct vc_data *vc;
+ unsigned int currcons = 0, i;
acquire_console_sem();
return 0;
}
+ for (i = 0; i < MAX_NR_CON_DRIVER; i++) {
+ struct con_driver *con_driver = ®istered_con_driver[i];
+
+ if (con_driver->con == NULL) {
+ con_driver->con = conswitchp;
+ con_driver->desc = display_desc;
+ con_driver->flag = CON_DRIVER_FLAG_INIT;
+ con_driver->first = 0;
+ con_driver->last = MAX_NR_CONSOLES - 1;
+ break;
+ }
+ }
+
+ for (i = 0; i < MAX_NR_CONSOLES; i++)
+ con_driver_map[i] = conswitchp;
+
init_timer(&console_timer);
console_timer.function = blank_screen_t;
if (blankinterval) {
* kmalloc is not running yet - we use the bootmem allocator.
*/
for (currcons = 0; currcons < MIN_NR_CONSOLES; currcons++) {
- vc_cons[currcons].d = (struct vc_data *)
- alloc_bootmem(sizeof(struct vc_data));
- vt_cons[currcons] = (struct vt_struct *)
- alloc_bootmem(sizeof(struct vt_struct));
- visual_init(currcons, 1);
- screenbuf = (unsigned short *) alloc_bootmem(screenbuf_size);
- kmalloced = 0;
- vc_init(currcons, video_num_lines, video_num_columns,
- currcons || !sw->con_save_screen);
+ vc_cons[currcons].d = vc = alloc_bootmem(sizeof(struct vc_data));
+ visual_init(vc, currcons, 1);
+ vc->vc_screenbuf = (unsigned short *)alloc_bootmem(vc->vc_screenbuf_size);
+ vc->vc_kmalloced = 0;
+ vc_init(vc, vc->vc_rows, vc->vc_cols,
+ currcons || !vc->vc_sw->con_save_screen);
}
currcons = fg_console = 0;
- master_display_fg = vc_cons[currcons].d;
- set_origin(currcons);
- save_screen(currcons);
- gotoxy(currcons,x,y);
- csi_J(currcons, 0);
- update_screen(fg_console);
+ master_display_fg = vc = vc_cons[currcons].d;
+ set_origin(vc);
+ save_screen(vc);
+ gotoxy(vc, vc->vc_x, vc->vc_y);
+ csi_J(vc, 0);
+ update_screen(vc);
printk("Console: %s %s %dx%d",
- can_do_color ? "colour" : "mono",
- display_desc, video_num_columns, video_num_lines);
+ vc->vc_can_do_color ? "colour" : "mono",
+ display_desc, vc->vc_cols, vc->vc_rows);
printable = 1;
printk("\n");
}
console_initcall(con_init);
-static struct tty_operations con_ops = {
+static const struct tty_operations con_ops = {
.open = con_open,
.close = con_close,
.write = con_write,
if (!console_driver)
panic("Couldn't allocate console driver\n");
console_driver->owner = THIS_MODULE;
- console_driver->devfs_name = "vc/";
console_driver->name = "tty";
console_driver->name_base = 1;
console_driver->major = TTY_MAJOR;
#ifdef CONFIG_MDA_CONSOLE
mda_console_init();
#endif
-#ifdef CONFIG_FRAMEBUFFER_CONSOLE
- fb_console_init();
-#endif
return 0;
}
#ifndef VT_SINGLE_DRIVER
+#include <linux/device.h>
-static void clear_buffer_attributes(int currcons)
-{
- unsigned short *p = (unsigned short *) origin;
- int count = screenbuf_size/2;
- int mask = hi_font_mask | 0xff;
+static struct class *vtconsole_class;
- for (; count > 0; count--, p++) {
- scr_writew((scr_readw(p)&mask) | (video_erase_char&~mask), p);
- }
-}
-
-/*
- * 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.
- */
-
-int take_over_console(const struct consw *csw, int first, int last, int deflt)
+static int bind_con_driver(const struct consw *csw, int first, int last,
+ int deflt)
{
- int i, j = -1;
- const char *desc;
- struct module *owner;
+ struct module *owner = csw->owner;
+ const char *desc = NULL;
+ struct con_driver *con_driver;
+ int i, j = -1, k = -1, retval = -ENODEV;
- owner = csw->owner;
if (!try_module_get(owner))
return -ENODEV;
acquire_console_sem();
- desc = csw->con_startup();
- if (!desc) {
- release_console_sem();
- module_put(owner);
- return -ENODEV;
+ /* check if driver is registered */
+ for (i = 0; i < MAX_NR_CON_DRIVER; i++) {
+ con_driver = ®istered_con_driver[i];
+
+ if (con_driver->con == csw) {
+ desc = con_driver->desc;
+ retval = 0;
+ break;
+ }
+ }
+
+ if (retval)
+ goto err;
+
+ if (!(con_driver->flag & CON_DRIVER_FLAG_INIT)) {
+ csw->con_startup();
+ con_driver->flag |= CON_DRIVER_FLAG_INIT;
}
+
if (deflt) {
if (conswitchp)
module_put(conswitchp->owner);
+
__module_get(owner);
conswitchp = csw;
}
+ first = max(first, con_driver->first);
+ last = min(last, con_driver->last);
+
for (i = first; i <= last; i++) {
int old_was_color;
- int currcons = i;
+ struct vc_data *vc = vc_cons[i].d;
if (con_driver_map[i])
module_put(con_driver_map[i]->owner);
__module_get(owner);
con_driver_map[i] = csw;
- if (!vc_cons[i].d || !vc_cons[i].d->vc_sw)
+ if (!vc || !vc->vc_sw)
continue;
j = i;
- if (IS_VISIBLE)
- save_screen(i);
- old_was_color = vc_cons[i].d->vc_can_do_color;
- vc_cons[i].d->vc_sw->con_deinit(vc_cons[i].d);
- origin = (unsigned long) screenbuf;
- visible_origin = origin;
- scr_end = origin + screenbuf_size;
- pos = origin + video_size_row*y + 2*x;
- visual_init(i, 0);
- update_attr(i);
+
+ if (CON_IS_VISIBLE(vc)) {
+ k = i;
+ save_screen(vc);
+ }
+
+ old_was_color = vc->vc_can_do_color;
+ vc->vc_sw->con_deinit(vc);
+ vc->vc_origin = (unsigned long)vc->vc_screenbuf;
+ visual_init(vc, i, 0);
+ set_origin(vc);
+ update_attr(vc);
/* If the console changed between mono <-> color, then
* the attributes in the screenbuf will be wrong. The
* following resets all attributes to something sane.
*/
- if (old_was_color != vc_cons[i].d->vc_can_do_color)
- clear_buffer_attributes(i);
-
- if (IS_VISIBLE)
- update_screen(i);
+ if (old_was_color != vc->vc_can_do_color)
+ clear_buffer_attributes(vc);
}
+
printk("Console: switching ");
if (!deflt)
printk("consoles %d-%d ", first+1, last+1);
- if (j >= 0)
+ if (j >= 0) {
+ struct vc_data *vc = vc_cons[j].d;
+
printk("to %s %s %dx%d\n",
- vc_cons[j].d->vc_can_do_color ? "colour" : "mono",
- desc, vc_cons[j].d->vc_cols, vc_cons[j].d->vc_rows);
- else
+ vc->vc_can_do_color ? "colour" : "mono",
+ desc, vc->vc_cols, vc->vc_rows);
+
+ if (k >= 0) {
+ vc = vc_cons[k].d;
+ update_screen(vc);
+ }
+ } else
printk("to %s\n", desc);
+ retval = 0;
+err:
release_console_sem();
+ module_put(owner);
+ return retval;
+};
+
+#ifdef CONFIG_VT_HW_CONSOLE_BINDING
+static int con_is_graphics(const struct consw *csw, int first, int last)
+{
+ int i, retval = 0;
+
+ for (i = first; i <= last; i++) {
+ struct vc_data *vc = vc_cons[i].d;
+
+ if (vc && vc->vc_mode == KD_GRAPHICS) {
+ retval = 1;
+ break;
+ }
+ }
+ return retval;
+}
+
+static int unbind_con_driver(const struct consw *csw, int first, int last,
+ int deflt)
+{
+ struct module *owner = csw->owner;
+ const struct consw *defcsw = NULL;
+ struct con_driver *con_driver = NULL, *con_back = NULL;
+ int i, retval = -ENODEV;
+
+ if (!try_module_get(owner))
+ return -ENODEV;
+
+ acquire_console_sem();
+
+ /* check if driver is registered and if it is unbindable */
+ for (i = 0; i < MAX_NR_CON_DRIVER; i++) {
+ con_driver = ®istered_con_driver[i];
+
+ if (con_driver->con == csw &&
+ con_driver->flag & CON_DRIVER_FLAG_MODULE) {
+ retval = 0;
+ break;
+ }
+ }
+
+ if (retval) {
+ release_console_sem();
+ goto err;
+ }
+
+ retval = -ENODEV;
+
+ /* check if backup driver exists */
+ for (i = 0; i < MAX_NR_CON_DRIVER; i++) {
+ con_back = ®istered_con_driver[i];
+
+ if (con_back->con &&
+ !(con_back->flag & CON_DRIVER_FLAG_MODULE)) {
+ defcsw = con_back->con;
+ retval = 0;
+ break;
+ }
+ }
+
+ if (retval) {
+ release_console_sem();
+ goto err;
+ }
+
+ if (!con_is_bound(csw)) {
+ release_console_sem();
+ goto err;
+ }
+
+ first = max(first, con_driver->first);
+ last = min(last, con_driver->last);
+
+ for (i = first; i <= last; i++) {
+ if (con_driver_map[i] == csw) {
+ module_put(csw->owner);
+ con_driver_map[i] = NULL;
+ }
+ }
+
+ if (!con_is_bound(defcsw)) {
+ const struct consw *defconsw = conswitchp;
+
+ defcsw->con_startup();
+ con_back->flag |= CON_DRIVER_FLAG_INIT;
+ /*
+ * vgacon may change the default driver to point
+ * to dummycon, we restore it here...
+ */
+ conswitchp = defconsw;
+ }
+
+ if (!con_is_bound(csw))
+ con_driver->flag &= ~CON_DRIVER_FLAG_INIT;
+
+ release_console_sem();
+ /* ignore return value, binding should not fail */
+ bind_con_driver(defcsw, first, last, deflt);
+err:
module_put(owner);
+ return retval;
+
+}
+
+static int vt_bind(struct con_driver *con)
+{
+ const struct consw *defcsw = NULL, *csw = NULL;
+ int i, more = 1, first = -1, last = -1, deflt = 0;
+
+ if (!con->con || !(con->flag & CON_DRIVER_FLAG_MODULE) ||
+ con_is_graphics(con->con, con->first, con->last))
+ goto err;
+
+ csw = con->con;
+
+ for (i = 0; i < MAX_NR_CON_DRIVER; i++) {
+ struct con_driver *con = ®istered_con_driver[i];
+
+ if (con->con && !(con->flag & CON_DRIVER_FLAG_MODULE)) {
+ defcsw = con->con;
+ break;
+ }
+ }
+
+ if (!defcsw)
+ goto err;
+
+ while (more) {
+ more = 0;
+
+ for (i = con->first; i <= con->last; i++) {
+ if (con_driver_map[i] == defcsw) {
+ if (first == -1)
+ first = i;
+ last = i;
+ more = 1;
+ } else if (first != -1)
+ break;
+ }
+
+ if (first == 0 && last == MAX_NR_CONSOLES -1)
+ deflt = 1;
+
+ if (first != -1)
+ bind_con_driver(csw, first, last, deflt);
+
+ first = -1;
+ last = -1;
+ deflt = 0;
+ }
+
+err:
return 0;
}
-void give_up_console(const struct consw *csw)
+static int vt_unbind(struct con_driver *con)
+{
+ const struct consw *csw = NULL;
+ int i, more = 1, first = -1, last = -1, deflt = 0;
+
+ if (!con->con || !(con->flag & CON_DRIVER_FLAG_MODULE) ||
+ con_is_graphics(con->con, con->first, con->last))
+ goto err;
+
+ csw = con->con;
+
+ while (more) {
+ more = 0;
+
+ for (i = con->first; i <= con->last; i++) {
+ if (con_driver_map[i] == csw) {
+ if (first == -1)
+ first = i;
+ last = i;
+ more = 1;
+ } else if (first != -1)
+ break;
+ }
+
+ if (first == 0 && last == MAX_NR_CONSOLES -1)
+ deflt = 1;
+
+ if (first != -1)
+ unbind_con_driver(csw, first, last, deflt);
+
+ first = -1;
+ last = -1;
+ deflt = 0;
+ }
+
+err:
+ return 0;
+}
+#else
+static inline int vt_bind(struct con_driver *con)
+{
+ return 0;
+}
+static inline int vt_unbind(struct con_driver *con)
+{
+ return 0;
+}
+#endif /* CONFIG_VT_HW_CONSOLE_BINDING */
+
+static ssize_t store_bind(struct device *dev, struct device_attribute *attr,
+ const char *buf, size_t count)
+{
+ struct con_driver *con = dev_get_drvdata(dev);
+ int bind = simple_strtoul(buf, NULL, 0);
+
+ if (bind)
+ vt_bind(con);
+ else
+ vt_unbind(con);
+
+ return count;
+}
+
+static ssize_t show_bind(struct device *dev, struct device_attribute *attr,
+ char *buf)
+{
+ struct con_driver *con = dev_get_drvdata(dev);
+ int bind = con_is_bound(con->con);
+
+ return snprintf(buf, PAGE_SIZE, "%i\n", bind);
+}
+
+static ssize_t show_name(struct device *dev, struct device_attribute *attr,
+ char *buf)
+{
+ struct con_driver *con = dev_get_drvdata(dev);
+
+ return snprintf(buf, PAGE_SIZE, "%s %s\n",
+ (con->flag & CON_DRIVER_FLAG_MODULE) ? "(M)" : "(S)",
+ con->desc);
+
+}
+
+static struct device_attribute device_attrs[] = {
+ __ATTR(bind, S_IRUGO|S_IWUSR, show_bind, store_bind),
+ __ATTR(name, S_IRUGO, show_name, NULL),
+};
+
+static int vtconsole_init_device(struct con_driver *con)
+{
+ int i;
+ int error = 0;
+
+ con->flag |= CON_DRIVER_FLAG_ATTR;
+ dev_set_drvdata(con->dev, con);
+ for (i = 0; i < ARRAY_SIZE(device_attrs); i++) {
+ error = device_create_file(con->dev, &device_attrs[i]);
+ if (error)
+ break;
+ }
+
+ if (error) {
+ while (--i >= 0)
+ device_remove_file(con->dev, &device_attrs[i]);
+ con->flag &= ~CON_DRIVER_FLAG_ATTR;
+ }
+
+ return error;
+}
+
+static void vtconsole_deinit_device(struct con_driver *con)
{
int i;
- for(i = 0; i < MAX_NR_CONSOLES; i++)
+ if (con->flag & CON_DRIVER_FLAG_ATTR) {
+ for (i = 0; i < ARRAY_SIZE(device_attrs); i++)
+ device_remove_file(con->dev, &device_attrs[i]);
+ con->flag &= ~CON_DRIVER_FLAG_ATTR;
+ }
+}
+
+/**
+ * con_is_bound - checks if driver is bound to the console
+ * @csw: console driver
+ *
+ * RETURNS: zero if unbound, nonzero if bound
+ *
+ * Drivers can call this and if zero, they should release
+ * all resources allocated on con_startup()
+ */
+int con_is_bound(const struct consw *csw)
+{
+ int i, bound = 0;
+
+ for (i = 0; i < MAX_NR_CONSOLES; i++) {
if (con_driver_map[i] == csw) {
- module_put(csw->owner);
- con_driver_map[i] = NULL;
+ bound = 1;
+ break;
}
+ }
+
+ return bound;
}
+EXPORT_SYMBOL(con_is_bound);
-#endif
+/**
+ * register_con_driver - register console driver to console layer
+ * @csw: console driver
+ * @first: the first console to take over, minimum value is 0
+ * @last: the last console to take over, maximum value is MAX_NR_CONSOLES -1
+ *
+ * DESCRIPTION: This function registers a console driver which can later
+ * bind to a range of consoles specified by @first and @last. It will
+ * also initialize the console driver by calling con_startup().
+ */
+int register_con_driver(const struct consw *csw, int first, int last)
+{
+ struct module *owner = csw->owner;
+ struct con_driver *con_driver;
+ const char *desc;
+ int i, retval = 0;
+
+ if (!try_module_get(owner))
+ return -ENODEV;
+
+ acquire_console_sem();
+
+ for (i = 0; i < MAX_NR_CON_DRIVER; i++) {
+ con_driver = ®istered_con_driver[i];
+
+ /* already registered */
+ if (con_driver->con == csw)
+ retval = -EINVAL;
+ }
+
+ if (retval)
+ goto err;
+
+ desc = csw->con_startup();
+
+ if (!desc)
+ goto err;
+
+ retval = -EINVAL;
+
+ for (i = 0; i < MAX_NR_CON_DRIVER; i++) {
+ con_driver = ®istered_con_driver[i];
+
+ if (con_driver->con == NULL) {
+ con_driver->con = csw;
+ con_driver->desc = desc;
+ con_driver->node = i;
+ con_driver->flag = CON_DRIVER_FLAG_MODULE |
+ CON_DRIVER_FLAG_INIT;
+ con_driver->first = first;
+ con_driver->last = last;
+ retval = 0;
+ break;
+ }
+ }
+
+ if (retval)
+ goto err;
+
+ con_driver->dev = device_create(vtconsole_class, NULL,
+ MKDEV(0, con_driver->node),
+ "vtcon%i", con_driver->node);
+
+ if (IS_ERR(con_driver->dev)) {
+ printk(KERN_WARNING "Unable to create device for %s; "
+ "errno = %ld\n", con_driver->desc,
+ PTR_ERR(con_driver->dev));
+ con_driver->dev = NULL;
+ } else {
+ vtconsole_init_device(con_driver);
+ }
+
+err:
+ release_console_sem();
+ module_put(owner);
+ return retval;
+}
+EXPORT_SYMBOL(register_con_driver);
+
+/**
+ * unregister_con_driver - unregister console driver from console layer
+ * @csw: console driver
+ *
+ * DESCRIPTION: All drivers that registers to the console layer must
+ * call this function upon exit, or if the console driver is in a state
+ * where it won't be able to handle console services, such as the
+ * framebuffer console without loaded framebuffer drivers.
+ *
+ * The driver must unbind first prior to unregistration.
+ */
+int unregister_con_driver(const struct consw *csw)
+{
+ int i, retval = -ENODEV;
+
+ acquire_console_sem();
+
+ /* cannot unregister a bound driver */
+ if (con_is_bound(csw))
+ goto err;
+
+ for (i = 0; i < MAX_NR_CON_DRIVER; i++) {
+ struct con_driver *con_driver = ®istered_con_driver[i];
+
+ if (con_driver->con == csw &&
+ con_driver->flag & CON_DRIVER_FLAG_MODULE) {
+ vtconsole_deinit_device(con_driver);
+ device_destroy(vtconsole_class,
+ MKDEV(0, con_driver->node));
+ con_driver->con = NULL;
+ con_driver->desc = NULL;
+ con_driver->dev = NULL;
+ con_driver->node = 0;
+ con_driver->flag = 0;
+ con_driver->first = 0;
+ con_driver->last = 0;
+ retval = 0;
+ break;
+ }
+ }
+err:
+ release_console_sem();
+ return retval;
+}
+EXPORT_SYMBOL(unregister_con_driver);
/*
- * Screen blanking
+ * 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.
+ *
+ * take_over_console is basically a register followed by unbind
*/
+int take_over_console(const struct consw *csw, int first, int last, int deflt)
+{
+ int err;
+
+ err = register_con_driver(csw, first, last);
+
+ if (!err)
+ bind_con_driver(csw, first, last, deflt);
+
+ return err;
+}
-static void set_vesa_blanking(char __user *p)
+/*
+ * give_up_console is a wrapper to unregister_con_driver. It will only
+ * work if driver is fully unbound.
+ */
+void give_up_console(const struct consw *csw)
{
- unsigned int mode;
- get_user(mode, p + 1);
- vesa_blank_mode = (mode < 4) ? mode : 0;
+ unregister_con_driver(csw);
}
+static int __init vtconsole_class_init(void)
+{
+ int i;
+
+ vtconsole_class = class_create(THIS_MODULE, "vtconsole");
+ if (IS_ERR(vtconsole_class)) {
+ printk(KERN_WARNING "Unable to create vt console class; "
+ "errno = %ld\n", PTR_ERR(vtconsole_class));
+ vtconsole_class = NULL;
+ }
+
+ /* Add system drivers to sysfs */
+ for (i = 0; i < MAX_NR_CON_DRIVER; i++) {
+ struct con_driver *con = ®istered_con_driver[i];
+
+ if (con->con && !con->dev) {
+ con->dev = device_create(vtconsole_class, NULL,
+ MKDEV(0, con->node),
+ "vtcon%i", con->node);
+
+ if (IS_ERR(con->dev)) {
+ printk(KERN_WARNING "Unable to create "
+ "device for %s; errno = %ld\n",
+ con->desc, PTR_ERR(con->dev));
+ con->dev = NULL;
+ } else {
+ vtconsole_init_device(con);
+ }
+ }
+ }
+
+ return 0;
+}
+postcore_initcall(vtconsole_class_init);
+
+#endif
+
/*
- * This is called by a timer handler
+ * Screen blanking
*/
-static 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, 0);
- break;
- case VESA_VSYNC_SUSPEND:
- case VESA_HSYNC_SUSPEND:
- c->vc_sw->con_blank(c, VESA_POWERDOWN+1, 0);
- break;
- }
+
+static int set_vesa_blanking(char __user *p)
+{
+ unsigned int mode;
+
+ if (get_user(mode, p + 1))
+ return -EFAULT;
+
+ vesa_blank_mode = (mode < 4) ? mode : 0;
+ return 0;
}
void do_blank_screen(int entering_gfx)
{
- int currcons = fg_console;
+ struct vc_data *vc = vc_cons[fg_console].d;
int i;
WARN_CONSOLE_UNLOCKED();
if (console_blanked) {
if (blank_state == blank_vesa_wait) {
blank_state = blank_off;
- vesa_powerdown();
-
+ vc->vc_sw->con_blank(vc, vesa_blank_mode + 1, 0);
}
return;
}
/* entering graphics mode? */
if (entering_gfx) {
- hide_cursor(currcons);
- save_screen(currcons);
- sw->con_blank(vc_cons[currcons].d, -1, 1);
+ hide_cursor(vc);
+ save_screen(vc);
+ vc->vc_sw->con_blank(vc, -1, 1);
console_blanked = fg_console + 1;
- set_origin(currcons);
+ set_origin(vc);
return;
}
/* don't blank graphics */
- if (vcmode != KD_TEXT) {
+ if (vc->vc_mode != KD_TEXT) {
console_blanked = fg_console + 1;
return;
}
- hide_cursor(currcons);
+ hide_cursor(vc);
del_timer_sync(&console_timer);
blank_timer_expired = 0;
- save_screen(currcons);
+ save_screen(vc);
/* In case we need to reset origin, blanking hook returns 1 */
- i = sw->con_blank(vc_cons[currcons].d, 1, 0);
+ i = vc->vc_sw->con_blank(vc, vesa_off_interval ? 1 : (vesa_blank_mode + 1), 0);
console_blanked = fg_console + 1;
if (i)
- set_origin(currcons);
+ set_origin(vc);
if (console_blank_hook && console_blank_hook(1))
return;
- if (vesa_off_interval) {
- blank_state = blank_vesa_wait,
+ if (vesa_off_interval && vesa_blank_mode) {
+ blank_state = blank_vesa_wait;
mod_timer(&console_timer, jiffies + vesa_off_interval);
}
-
- if (vesa_blank_mode)
- sw->con_blank(vc_cons[currcons].d, vesa_blank_mode + 1, 0);
}
-
+EXPORT_SYMBOL(do_blank_screen);
/*
* Called by timer as well as from vt_console_driver
*/
void do_unblank_screen(int leaving_gfx)
{
- int currcons;
+ struct vc_data *vc;
+
+ /* This should now always be called from a "sane" (read: can schedule)
+ * context for the sake of the low level drivers, except in the special
+ * case of oops_in_progress
+ */
+ if (!oops_in_progress)
+ might_sleep();
WARN_CONSOLE_UNLOCKED();
printk("unblank_screen: tty %d not allocated ??\n", fg_console+1);
return;
}
- currcons = fg_console;
- if (vcmode != KD_TEXT)
+ vc = vc_cons[fg_console].d;
+ if (vc->vc_mode != KD_TEXT)
return; /* but leave console_blanked != 0 */
if (blankinterval) {
}
console_blanked = 0;
- if (sw->con_blank(vc_cons[currcons].d, 0, leaving_gfx))
+ if (vc->vc_sw->con_blank(vc, 0, leaving_gfx))
/* Low-level driver cannot restore -> do it ourselves */
- update_screen(fg_console);
+ update_screen(vc);
if (console_blank_hook)
console_blank_hook(0);
- set_palette(currcons);
- set_cursor(fg_console);
+ set_palette(vc);
+ set_cursor(vc);
}
+EXPORT_SYMBOL(do_unblank_screen);
/*
* This is called by the outside world to cause a forced unblank, mostly for
}
/*
- * We defer the timer blanking to work queue so it can take the console semaphore
+ * We defer the timer blanking to work queue so it can take the console mutex
* (console operations can still happen at irq time, but only from printk which
- * has the console semaphore. Not perfect yet, but better than no locking
+ * has the console mutex. Not perfect yet, but better than no locking
*/
static void blank_screen_t(unsigned long dummy)
{
+ if (unlikely(!keventd_up())) {
+ mod_timer(&console_timer, jiffies + blankinterval);
+ return;
+ }
blank_timer_expired = 1;
schedule_work(&console_work);
}
{
WARN_CONSOLE_UNLOCKED();
+ /* Add this so we quickly catch whoever might call us in a non
+ * safe context. Nowadays, unblank_screen() isn't to be called in
+ * atomic contexts and is allowed to schedule (with the special case
+ * of oops_in_progress, but that isn't of any concern for this
+ * function. --BenH.
+ */
+ might_sleep();
+
/* This isn't perfectly race free, but a race here would be mostly harmless,
* at worse, we'll do a spurrious blank and it's unlikely
*/
del_timer(&console_timer);
blank_timer_expired = 0;
- if (ignore_poke || !vt_cons[fg_console] || vt_cons[fg_console]->vc_mode == KD_GRAPHICS)
+ if (ignore_poke || !vc_cons[fg_console].d || vc_cons[fg_console].d->vc_mode == KD_GRAPHICS)
return;
if (console_blanked)
unblank_screen();
* Palettes
*/
-void set_palette(int currcons)
+static void set_palette(struct vc_data *vc)
{
WARN_CONSOLE_UNLOCKED();
- if (vcmode != KD_GRAPHICS)
- sw->con_set_palette(vc_cons[currcons].d, color_table);
+ if (vc->vc_mode != KD_GRAPHICS)
+ vc->vc_sw->con_set_palette(vc, color_table);
}
static int set_get_cmap(unsigned char __user *arg, int set)
vc_cons[i].d->vc_palette[k++] = default_grn[j];
vc_cons[i].d->vc_palette[k++] = default_blu[j];
}
- set_palette(i);
+ set_palette(vc_cons[i].d);
}
}
return 0;
return rc;
}
-void reset_palette(int currcons)
+void reset_palette(struct vc_data *vc)
{
int j, k;
for (j=k=0; j<16; j++) {
- palette[k++] = default_red[j];
- palette[k++] = default_grn[j];
- palette[k++] = default_blu[j];
+ vc->vc_palette[k++] = default_red[j];
+ vc->vc_palette[k++] = default_grn[j];
+ vc->vc_palette[k++] = default_blu[j];
}
- set_palette(currcons);
+ set_palette(vc);
}
/*
#define max_font_size 65536
-int con_font_get(int currcons, struct console_font_op *op)
+static int con_font_get(struct vc_data *vc, struct console_font_op *op)
{
struct console_font font;
int rc = -EINVAL;
int c;
- if (vt_cons[currcons]->vc_mode != KD_TEXT)
+ if (vc->vc_mode != KD_TEXT)
return -EINVAL;
if (op->data) {
font.data = NULL;
acquire_console_sem();
- if (sw->con_font_get)
- rc = sw->con_font_get(vc_cons[currcons].d, &font);
+ if (vc->vc_sw->con_font_get)
+ rc = vc->vc_sw->con_font_get(vc, &font);
else
rc = -ENOSYS;
release_console_sem();
if (rc)
goto out;
+ op->height = font.height;
+ op->width = font.width;
+ op->charcount = font.charcount;
+
if (op->data && copy_to_user(op->data, font.data, c))
rc = -EFAULT;
return rc;
}
-int con_font_set(int currcons, struct console_font_op *op)
+static int con_font_set(struct vc_data *vc, struct console_font_op *op)
{
struct console_font font;
int rc = -EINVAL;
int size;
- if (vt_cons[currcons]->vc_mode != KD_TEXT)
+ if (vc->vc_mode != KD_TEXT)
return -EINVAL;
if (!op->data)
return -EINVAL;
return -EFAULT;
}
acquire_console_sem();
- if (sw->con_font_set)
- rc = sw->con_font_set(vc_cons[currcons].d, &font, op->flags);
+ if (vc->vc_sw->con_font_set)
+ rc = vc->vc_sw->con_font_set(vc, &font, op->flags);
else
rc = -ENOSYS;
release_console_sem();
return rc;
}
-int con_font_default(int currcons, struct console_font_op *op)
+static int con_font_default(struct vc_data *vc, struct console_font_op *op)
{
struct console_font font = {.width = op->width, .height = op->height};
char name[MAX_FONT_NAME];
char *s = name;
int rc;
- if (vt_cons[currcons]->vc_mode != KD_TEXT)
+ if (vc->vc_mode != KD_TEXT)
return -EINVAL;
if (!op->data)
name[MAX_FONT_NAME - 1] = 0;
acquire_console_sem();
- if (sw->con_font_default)
- rc = sw->con_font_default(vc_cons[currcons].d, &font, s);
+ if (vc->vc_sw->con_font_default)
+ rc = vc->vc_sw->con_font_default(vc, &font, s);
else
rc = -ENOSYS;
release_console_sem();
return rc;
}
-int con_font_copy(int currcons, struct console_font_op *op)
+static int con_font_copy(struct vc_data *vc, struct console_font_op *op)
{
int con = op->height;
- struct vc_data *vc;
int rc;
- if (vt_cons[currcons]->vc_mode != KD_TEXT)
+ if (vc->vc_mode != KD_TEXT)
return -EINVAL;
acquire_console_sem();
- vc = vc_cons[currcons].d;
- if (!sw->con_font_copy)
+ if (!vc->vc_sw->con_font_copy)
rc = -ENOSYS;
else if (con < 0 || !vc_cons_allocated(con))
rc = -ENOTTY;
else if (con == vc->vc_num) /* nothing to do */
rc = 0;
else
- rc = sw->con_font_copy(vc, con);
+ rc = vc->vc_sw->con_font_copy(vc, con);
release_console_sem();
return rc;
}
-int con_font_op(int currcons, struct console_font_op *op)
+int con_font_op(struct vc_data *vc, struct console_font_op *op)
{
switch (op->op) {
case KD_FONT_OP_SET:
- return con_font_set(currcons, op);
+ return con_font_set(vc, op);
case KD_FONT_OP_GET:
- return con_font_get(currcons, op);
+ return con_font_get(vc, op);
case KD_FONT_OP_SET_DEFAULT:
- return con_font_default(currcons, op);
+ return con_font_default(vc, op);
case KD_FONT_OP_COPY:
- return con_font_copy(currcons, op);
+ return con_font_copy(vc, op);
}
return -ENOSYS;
}
*/
/* used by selection */
-u16 screen_glyph(int currcons, int offset)
+u16 screen_glyph(struct vc_data *vc, int offset)
{
- u16 w = scr_readw(screenpos(currcons, offset, 1));
+ u16 w = scr_readw(screenpos(vc, offset, 1));
u16 c = w & 0xff;
- if (w & hi_font_mask)
+ if (w & vc->vc_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)
+unsigned short *screen_pos(struct vc_data *vc, int w_offset, int viewed)
{
- return screenpos(currcons, 2 * w_offset, viewed);
+ return screenpos(vc, 2 * w_offset, viewed);
}
-void getconsxy(int currcons, unsigned char *p)
+void getconsxy(struct vc_data *vc, unsigned char *p)
{
- p[0] = x;
- p[1] = y;
+ p[0] = vc->vc_x;
+ p[1] = vc->vc_y;
}
-void putconsxy(int currcons, unsigned char *p)
+void putconsxy(struct vc_data *vc, unsigned char *p)
{
- gotoxy(currcons, p[0], p[1]);
- set_cursor(currcons);
+ hide_cursor(vc);
+ gotoxy(vc, p[0], p[1]);
+ set_cursor(vc);
}
-u16 vcs_scr_readw(int currcons, const u16 *org)
+u16 vcs_scr_readw(struct vc_data *vc, const u16 *org)
{
- if ((unsigned long)org == pos && softcursor_original != -1)
+ if ((unsigned long)org == vc->vc_pos && softcursor_original != -1)
return softcursor_original;
return scr_readw(org);
}
-void vcs_scr_writew(int currcons, u16 val, u16 *org)
+void vcs_scr_writew(struct vc_data *vc, u16 val, u16 *org)
{
scr_writew(val, org);
- if ((unsigned long)org == pos) {
+ if ((unsigned long)org == vc->vc_pos) {
softcursor_original = -1;
- add_softcursor(currcons);
- }
-}
-
-static int pm_con_request(struct pm_dev *dev, pm_request_t rqst, void *data)
-{
- switch (rqst)
- {
- case PM_RESUME:
- acquire_console_sem();
- unblank_screen();
- release_console_sem();
- break;
- case PM_SUSPEND:
- acquire_console_sem();
- do_blank_screen(0);
- release_console_sem();
- break;
+ add_softcursor(vc);
}
- return 0;
}
/*
EXPORT_SYMBOL(default_red);
EXPORT_SYMBOL(default_grn);
EXPORT_SYMBOL(default_blu);
-EXPORT_SYMBOL(vc_cons_allocated);
EXPORT_SYMBOL(update_region);
EXPORT_SYMBOL(redraw_screen);
EXPORT_SYMBOL(vc_resize);
+EXPORT_SYMBOL(vc_lock_resize);
EXPORT_SYMBOL(fg_console);
EXPORT_SYMBOL(console_blank_hook);
EXPORT_SYMBOL(console_blanked);
-EXPORT_SYMBOL(vt_cons);
EXPORT_SYMBOL(vc_cons);
#ifndef VT_SINGLE_DRIVER
EXPORT_SYMBOL(take_over_console);