BigOS/kernel/console.c
2022-12-13 13:29:17 +08:00

327 lines
9.8 KiB
C

#include "type.h"
#include "stdio.h"
#include "const.h"
#include "protect.h"
#include "string.h"
#include "fs.h"
#include "proc.h"
#include "tty.h"
#include "console.h"
#include "global.h"
#include "keyboard.h"
#include "proto.h"
#include "x86.h"
/* local routines */
static void set_cursor(unsigned int position);
static void set_video_start_addr(u32 addr);
static void flush(CONSOLE* con);
static void w_copy(unsigned int dst, const unsigned int src, int size);
static void clear_screen(int pos, int len);
void scroll_screen(CONSOLE* con, int dir);
/*****************************************************************************
* init_screen
*****************************************************************************/
/**
* Initialize the console of a certain tty.
*
* @param tty Whose console is to be initialized.
*****************************************************************************/
void init_screen(TTY* tty)
{
int nr_tty = tty - tty_table;
tty->console = console_table + nr_tty;
/*
* NOTE:
* variables related to `position' and `size' below are
* in WORDs, but not in BYTEs.
*/
int v_mem_size = V_MEM_SIZE >> 1; /* size of Video Memory */
int size_per_con = (v_mem_size / NR_CONSOLES)/80*80;
tty->console->orig = nr_tty * size_per_con;
tty->console->con_size = size_per_con / SCR_WIDTH * SCR_WIDTH;
tty->console->cursor = tty->console->crtc_start = tty->console->orig;
tty->console->is_full = 0;
tty->console->current_line = 0;
if(nr_tty==0){
tty->console->cursor = disp_pos / 2;
}
const char prompt[] = "[TTY #?]\n";
const char * p = prompt;
for (; *p; p++){
out_char(tty->console, *p == '?' ? nr_tty + '0' : *p);
}
set_cursor(tty->console->cursor);
}
/*****************************************************************************
* out_char
*****************************************************************************/
/**
* Print a char in a certain console.
*
* @param con The console to which the char is printed.
* @param ch The char to print.
*****************************************************************************/
void out_char(CONSOLE* con, char ch)
{
disable_int();
int cursor_x = (con->cursor - con->orig) % SCR_WIDTH;
int cursor_y = (con->cursor - con->orig) / SCR_WIDTH;
switch(ch) {
case '\n':
con->cursor = con->orig + SCR_WIDTH * (cursor_y + 1);
break;
case '\b':
if (con->cursor > con->orig) {
con->cursor--;
//*(pch - 2) = ' ';
//*(pch - 1) = DEFAULT_CHAR_COLOR;
disp_pos = con->cursor*2;
write_char(' ');
}
break;
default:
//*pch++ = ch;
//*pch++ = DEFAULT_CHAR_COLOR;
disp_pos = con->cursor*2;
write_char(ch);
con->cursor++;
break;
}
if (con->cursor - con->orig >= con->con_size) {
cursor_x = (con->cursor - con->orig) % SCR_WIDTH;
cursor_y = (con->cursor - con->orig) / SCR_WIDTH;
int cp_orig = con->orig + (cursor_y + 1) * SCR_WIDTH - SCR_SIZE;
w_copy(con->orig, cp_orig, SCR_SIZE - SCR_WIDTH);
con->crtc_start = con->orig;
con->cursor = con->orig + (SCR_SIZE - SCR_WIDTH) + cursor_x;
clear_screen(con->cursor, SCR_WIDTH);
if (!con->is_full)
con->is_full = 1;
}
//assert(con->cursor - con->orig < con->con_size);
while (con->cursor >= con->crtc_start + SCR_SIZE ||
con->cursor < con->crtc_start) {
scroll_screen(con, SCR_UP);
clear_screen(con->cursor, SCR_WIDTH);
}
flush(con);
enable_int();
}
/*****************************************************************************
* clear_screen
*****************************************************************************/
/**
* Write whitespaces to the screen.
*
* @param pos Write from here.
* @param len How many whitespaces will be written.
*****************************************************************************/
static void clear_screen(int pos, int len)
{
u8 * pch = (u8*)K_PHY2LIN(V_MEM_BASE + pos * 2);
while (--len >= 0) {
*pch++ = ' ';
*pch++ = DEFAULT_CHAR_COLOR;
}
}
/*****************************************************************************
* is_current_console
*****************************************************************************/
/**
* Uses `nr_current_console' to determine if a console is the current one.
*
* @param con Ptr to console.
*
* @return TRUE if con is the current console.
*****************************************************************************/
int is_current_console(CONSOLE* con)
{
return (con == &console_table[current_console]);
}
/*****************************************************************************
* set_cursor
*****************************************************************************/
/**
* Display the cursor by setting CRTC (6845 compatible) registers.
*
* @param position Position of the cursor based on the beginning of the video
* memory. Note that it counts in WORDs, not in BYTEs.
*****************************************************************************/
static void set_cursor(unsigned int position)
{
disable_int();
outb(CRTC_ADDR_REG, CURSOR_H);
outb(CRTC_DATA_REG, (position >> 8) & 0xFF);
outb(CRTC_ADDR_REG, CURSOR_L);
outb(CRTC_DATA_REG, position & 0xFF);
enable_int();
}
/*****************************************************************************
* set_video_start_addr
*****************************************************************************/
/**
* Routine for hardware screen scrolling.
*
* @param addr Offset in the video memory.
*****************************************************************************/
static void set_video_start_addr(u32 addr)
{
disable_int();
outb(CRTC_ADDR_REG, START_ADDR_H);
outb(CRTC_DATA_REG, (addr >> 8) & 0xFF);
outb(CRTC_ADDR_REG, START_ADDR_L);
outb(CRTC_DATA_REG, addr & 0xFF);
enable_int();
}
/*****************************************************************************
* select_console
*****************************************************************************/
/**
* Select a console as the current.
*
* @param nr_console Console nr, range in [0, NR_CONSOLES-1].
*****************************************************************************/
void select_console(int nr_console)
{
if ((nr_console < 0) || (nr_console >= NR_CONSOLES)) return;
flush(&console_table[current_console = nr_console]);
}
/*****************************************************************************
* scroll_screen
*****************************************************************************/
/**
* Scroll the screen.
*
* Note that scrolling UP means the content of the screen will go upwards, so
* that the user can see lines below the bottom. Similarly scrolling DOWN means
* the content of the screen will go downwards so that the user can see lines
* above the top.
*
* When there is no line below the bottom of the screen, scrolling UP takes no
* effects; when there is no line above the top of the screen, scrolling DOWN
* takes no effects.
*
* @param con The console whose screen is to be scrolled.
* @param dir SCR_UP : scroll the screen upwards;
* SCR_DN : scroll the screen downwards
*****************************************************************************/
void scroll_screen(CONSOLE* con, int dir)
{
/*
* variables below are all in-console-offsets (based on con->orig)
*/
int oldest; /* addr of the oldest available line in the console */
int newest; /* .... .. ... latest ......... .... .. ... ....... */
int scr_top;/* position of the top of current screen */
newest = (con->cursor - con->orig) / SCR_WIDTH * SCR_WIDTH;
oldest = con->is_full ? (newest + SCR_WIDTH) % con->con_size : 0;
scr_top = con->crtc_start - con->orig;
if (dir == SCR_DN) {
if (!con->is_full && scr_top > 0) {
con->crtc_start -= SCR_WIDTH;
}
else if (con->is_full && scr_top != oldest) {
if (con->cursor - con->orig >= con->con_size - SCR_SIZE) {
if (con->crtc_start != con->orig)
con->crtc_start -= SCR_WIDTH;
}
else if (con->crtc_start == con->orig) {
scr_top = con->con_size - SCR_SIZE;
con->crtc_start = con->orig + scr_top;
}
else {
con->crtc_start -= SCR_WIDTH;
}
}
}
else if (dir == SCR_UP) {
if (!con->is_full && newest >= scr_top + SCR_SIZE) {
con->crtc_start += SCR_WIDTH;
}
else if (con->is_full && scr_top + SCR_SIZE - SCR_WIDTH != newest) {
if (scr_top + SCR_SIZE == con->con_size)
con->crtc_start = con->orig;
else
con->crtc_start += SCR_WIDTH;
}
}
else {
//assert(dir == SCR_DN || dir == SCR_UP);
}
flush(con);
}
/*****************************************************************************
* flush
*****************************************************************************/
/**
* Set the cursor and starting address of a console by writing the
* CRT Controller Registers.
*
* @param con The console to be set.
*****************************************************************************/
static void flush(CONSOLE* con)
{
if (is_current_console(con)) {
set_cursor(con->cursor);
set_video_start_addr(con->crtc_start);
}
}
/*****************************************************************************
* w_copy
*****************************************************************************/
/**
* Copy data in WORDS.
*
* Note that the addresses of dst and src are not pointers, but integers, 'coz
* in most cases we pass integers into it as parameters.
*
* @param dst Addr of destination.
* @param src Addr of source.
* @param size How many words will be copied.
*****************************************************************************/
static void w_copy(unsigned int dst, const unsigned int src, int size)
{
memcpy((void*)(V_MEM_BASE + (dst << 1)),
(void*)(V_MEM_BASE + (src << 1)),
size << 1);
}