/*
* linux/kernel/console.c
*
* (C) 1991 Linus Torvalds
*/
/*
* console.c
*
* This module implements the console io functions
* 'void con_init(void)'
* 'void con_write(struct tty_queue * queue)'
* Hopefully this will be a rather complete VT102 implementation.
*
* Beeping thanks to John T Kohl.
*
* Virtual Consoles, Screen Blanking, Screen Dumping, Color, Graphics
* Chars, and VT100 enhancements by Peter MacDonald.
*/
/*
* NOTE!!! We sometimes disable and enable interrupts for a short while
* (to put a word in video IO), but this will work even for keyboard
* interrupts. We know interrupts aren't enabled when getting a keyboard
* interrupt, as we use trap-gates. Hopefully all is well.
*/
/*
* Code to check for different video-cards mostly by Galen Hunt,
* <g-hunt@ee.utah.edu>
*/
#include <linux/sched.h>
#include <linux/tty.h>
#include <linux/config.h>
#include <linux/kernel.h>
#include <asm/io.h>
#include <asm/system.h>
#include <asm/segment.h>
#include <string.h>
#include <errno.h>
#define DEF_TERMIOS \
(struct termios) { \
ICRNL, \
OPOST | ONLCR, \
0, \
IXON | ISIG | ICANON | ECHO | ECHOCTL | ECHOKE, \
0, \
INIT_C_CC \
}
/*
* These are set up by the setup-routine at boot-time:
*/
#define ORIG_X (*(unsigned char *)0x90000)
#define ORIG_Y (*(unsigned char *)0x90001)
#define ORIG_VIDEO_PAGE (*(unsigned short *)0x90004)
#define ORIG_VIDEO_MODE ((*(unsigned short *)0x90006) & 0xff)
#define ORIG_VIDEO_COLS (((*(unsigned short *)0x90006) & 0xff00) >> 8)
#define ORIG_VIDEO_LINES ((*(unsigned short *)0x9000e) & 0xff)
#define ORIG_VIDEO_EGA_AX (*(unsigned short *)0x90008)
#define ORIG_VIDEO_EGA_BX (*(unsigned short *)0x9000a)
#define ORIG_VIDEO_EGA_CX (*(unsigned short *)0x9000c)
#define VIDEO_TYPE_MDA 0x10 /* Monochrome Text Display */
#define VIDEO_TYPE_CGA 0x11 /* CGA Display */
#define VIDEO_TYPE_EGAM 0x20 /* EGA/VGA in Monochrome Mode */
#define VIDEO_TYPE_EGAC 0x21 /* EGA/VGA in Color Mode */
#define NPAR 16
int NR_CONSOLES = 0;
extern void keyboard_interrupt(void);
static unsigned char video_type; /* Type of display being used */
static unsigned long video_num_columns; /* Number of text columns */
static unsigned long video_mem_base; /* Base of video memory */
static unsigned long video_mem_term; /* End of video memory */
static unsigned long video_size_row; /* Bytes per row */
static unsigned long video_num_lines; /* Number of test lines */
static unsigned char video_page; /* Initial video page */
static unsigned short video_port_reg; /* Video register select port */
static unsigned short video_port_val; /* Video register value port */
static int can_do_colour = 0;
static struct {
unsigned short vc_video_erase_char;
unsigned char vc_attr;
unsigned char vc_def_attr;
int vc_bold_attr;
unsigned long vc_ques;
unsigned long vc_state;
unsigned long vc_restate;
unsigned long vc_checkin;
unsigned long vc_origin; /* Used for EGA/VGA fast scroll */
unsigned long vc_scr_end; /* Used for EGA/VGA fast scroll */
unsigned long vc_pos;
unsigned long vc_x,vc_y;
unsigned long vc_top,vc_bottom;
unsigned long vc_npar,vc_par[NPAR];
unsigned long vc_video_mem_start; /* Start of video RAM */
unsigned long vc_video_mem_end; /* End of video RAM (sort of) */
unsigned int vc_saved_x;
unsigned int vc_saved_y;
unsigned int vc_iscolor;
char * vc_translate;
} vc_cons [MAX_CONSOLES];
#define origin (vc_cons[currcons].vc_origin)
#define scr_end (vc_cons[currcons].vc_scr_end)
#define pos (vc_cons[currcons].vc_pos)
#define top (vc_cons[currcons].vc_top)
#define bottom (vc_cons[currcons].vc_bottom)
#define x (vc_cons[currcons].vc_x)
#define y (vc_cons[currcons].vc_y)
#define state (vc_cons[currcons].vc_state)
#define restate (vc_cons[currcons].vc_restate)
#define checkin (vc_cons[currcons].vc_checkin)
#define npar (vc_cons[currcons].vc_npar)
#define par (vc_cons[currcons].vc_par)
#define ques (vc_cons[currcons].vc_ques)
#define attr (vc_cons[currcons].vc_attr)
#define saved_x (vc_cons[currcons].vc_saved_x)
#define saved_y (vc_cons[currcons].vc_saved_y)
#define translate (vc_cons[currcons].vc_translate)
#define video_mem_start (vc_cons[currcons].vc_video_mem_start)
#define video_mem_end (vc_cons[currcons].vc_video_mem_end)
#define def_attr (vc_cons[currcons].vc_def_attr)
#define video_erase_char (vc_cons[currcons].vc_video_erase_char)
#define iscolor (vc_cons[currcons].vc_iscolor)
int blankinterval = 0;
int blankcount = 0;
static void sysbeep(void);
/*
* this is what the terminal answers to a ESC-Z or csi0c
* query (= vt100 response).
*/
#define RESPONSE "\033[?1;2c"
static char * translations[] = {
/* normal 7-bit ascii */
" !\"#$%&'()*+,-./0123456789:;<=>?"
"@ABCDEFGHIJKLMNOPQRSTUVWXYZ[\\]^_"
"`abcdefghijklmnopqrstuvwxyz{|}~ ",
/* vt100 graphics */
" !\"#$%&'()*+,-./0123456789:;<=>?"
"@ABCDEFGHIJKLMNOPQRSTUVWXYZ[\\]^ "
"\004\261\007\007\007\007\370\361\007\007\275\267\326\323\327\304"
"\304\304\304\304\307\266\320\322\272\363\362\343\\007\234\007 "
};
#define NORM_TRANS (translations[0])
#define GRAF_TRANS (translations[1])
/* NOTE! gotoxy thinks x==video_num_columns is ok */
static inline void gotoxy(int currcons, int new_x,unsigned int new_y)
{
if (new_x > video_num_columns || new_y >= video_num_lines)
return;
x = new_x;
y = new_y;
pos = origin + y*video_size_row + (x<<1);
}
static inline void set_origin(int currcons)
{
if (video_type != VIDEO_TYPE_EGAC && video_type != VIDEO_TYPE_EGAM)
return;
if (currcons != fg_console)
return;
cli();
outb_p(12, video_port_reg);
outb_p(0xff&((origin-video_mem_base)>>9), video_port_val);
outb_p(13, video_port_reg);
outb_p(0xff&((origin-video_mem_base)>>1), video_port_val);
sti();
}
static void scrup(int currcons)
{
if (bottom<=top)
return;
if (video_type == VIDEO_TYPE_EGAC || video_type == VIDEO_TYPE_EGAM)
{
if (!top && bottom == video_num_lines) {
origin += video_size_row;
pos += video_size_row;
scr_end += video_size_row;
if (scr_end > video_mem_end) {
__asm__("cld\n\t"
"rep\n\t"
"movsl\n\t"
"movl _video_num_columns,%1\n\t"
"rep\n\t"
"stosw"
::"a" (video_erase_char),
"c" ((video_num_lines-1)*video_num_columns>>1),
"D" (video_mem_start),
"S" (origin)
:"cx","di","si");
scr_end -= origin-video_mem_start;
pos -= origin-video_mem_start;
origin = video_mem_start;
} else {
__asm__("cld\n\t"
"rep\n\t"
"stosw"
::"a" (video_erase_char),
"c" (video_num_columns),
"D" (scr_end-video_size_row)
:"cx","di");
}
set_origin(currcons);
} else {
__asm__("cld\n\t"
"rep\n\t"
"movsl\n\t"
"movl _video_num_columns,%%ecx\n\t"
"rep\n\t"
"stosw"
::"a" (video_erase_char),
"c" ((bottom-top-1)*video_num_columns>>1),
"D" (origin+video_size_row*top),
"S" (origin+video_size_row*(top+1))
:"cx","di","si");
}
}
else /* Not EGA/VGA */
{
__asm__("cld\n\t"
"rep\n\t"
"movsl\n\t"
"movl _video_num_columns,%%ecx\n\t"
"rep\n\t"
"stosw"
::"a" (video_erase_char),
"c" ((bottom-top-1)*video_num_columns>>1),
"D" (origin+video_size_row*top),
"S" (origin+video_size_row*(top+1))
:"cx","di","si");
}
}
static void scrdown(int currcons)
{
if (bottom <= top)
return;
if (video_type == VIDEO_TYPE_EGAC || video_type == VIDEO_TYPE_EGAM)
{
__asm__("std\n\t"
"rep\n\t"
"movsl\n\t"
"addl $2,%%edi\n\t" /* %edi has been decremented by 4 */
"movl _video_num_columns,%%ecx\n\t"
"rep\n\t"
"stosw"
::"a" (video_erase_char),
"c" ((bottom-top-1)*video_num_columns>>1),
"D" (origin+video_size_row*bottom-4),
"S" (origin+video_size_row*(bottom-1)-4)
:"ax","cx","di","si");
}
else /* Not EGA/VGA */
{
__asm__("std\n\t"
"rep\n\t"
"movsl\n\t"
"addl $2,%%edi\n\t" /* %edi has been decremented by 4 */
"movl _video_num_columns,%%ecx\n\t"
"rep\n\t"
"stosw"
::"a" (video_erase_char),
"c" ((bottom-top