add simple console before tty init

This commit is contained in:
catfood 2023-01-08 11:12:41 +08:00
parent a3a2bb4cfe
commit bb51f9775a
5 changed files with 103 additions and 316 deletions

View File

@ -17,14 +17,20 @@
/* CONSOLE */
typedef struct s_console
{
unsigned int crtc_start; /* set CRTC start addr reg */
unsigned int orig; /* start addr of the console */
unsigned int con_size; /* how many words does the console have */
unsigned int cursor;
int is_full;
unsigned int current_line;
unsigned int row;
unsigned int col;
unsigned int buf_head; // for futher restore after true tty initialized
unsigned int buf_tail;
char *buf;
} CONSOLE;
void simpleconsole_init();
void simpleconsole_write(char* buf, int nr);
void simpleconsole_transfer(void (*write)(char ch));
void simpleconsole_setcur(int row, int col);
#define CON_MAX_LOGBUF 1024
#define SCR_UP 1 /* scroll upward */
#define SCR_DN -1 /* scroll downward */

View File

@ -57,6 +57,7 @@ typedef struct n_tty
void (*write)(struct n_tty *tty, char ch);
int (*read)(struct n_tty *tty, char* buf, int nr);
void (*recvbuf)(struct n_tty *tty, u32 ch);
int (*ioctl)(struct n_tty *tty, u32 cmd, long arg);
} NTTY;
enum CSI_state
@ -104,11 +105,6 @@ typedef struct serial_buf
#include "console.h"
void select_console(int nr_console);
void init_screen(TTY *tty);
void out_char(CONSOLE *con, char ch);
int is_current_console(CONSOLE *con);
NTTY *get_tty(const int nr_tty);
void vga_tty_init(NTTY *tty);

View File

@ -1,3 +1,4 @@
// A simple, vga textmode console ready to use before tty init
#include "type.h"
#include "stdio.h"
#include "const.h"
@ -12,175 +13,37 @@
#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);
#define INDEX(row, col) ((row)*SCR_WIDTH + (col))
/*****************************************************************************
* init_screen
*****************************************************************************/
/**
* Initialize the console of a certain tty.
*
* @param tty Whose console is to be initialized.
*****************************************************************************/
void init_screen(TTY *tty)
static char logbuf[CON_MAX_LOGBUF];
static CONSOLE con = {
.row = 0,
.col = 0,
.buf = logbuf,
.buf_head = 0,
.buf_tail = 0
};
static inline void vga_put_raw(u32 pos, u16 dat)
{
int nr_tty = 0;
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);
u16 *pch = (u16 *)K_PHY2LIN(V_MEM_BASE) + pos;
*pch = dat;
}
static inline void write_char_c(int pos, char ch)
// simple scroll, just abandon those scrolled up
static void scroll()
{
u16 *pch = (u16 *)K_PHY2LIN(V_MEM_BASE + pos);
*pch = (0x0f << 8) | ch;
}
/*****************************************************************************
* 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_c(disp_pos, ' ');
u16* video_mem = (u16 *)K_PHY2LIN(V_MEM_BASE);
for (int i = 0; i < SCR_HEIGHT - 1; ++ i) {
for (int j = 0; j < SCR_WIDTH; ++ j) {
video_mem[INDEX(i, j)] = video_mem[INDEX(i+1, j)];
}
break;
default:
//*pch++ = ch;
//*pch++ = DEFAULT_CHAR_COLOR;
disp_pos = con->cursor * 2;
write_char_c(disp_pos, 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++ = (u8)(DEFAULT_CHAR_COLOR >> 8);
for (int j = 0; j < SCR_WIDTH; ++ j) {
video_mem[INDEX(SCR_HEIGHT-1, j)] = BLANK;
}
}
/*****************************************************************************
* 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();
@ -191,152 +54,78 @@ static void set_cursor(unsigned int position)
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)
void simpleconsole_init()
{
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();
con.row = 0;
con.col = 0;
con.buf = logbuf;
con.buf_head = 0;
con.buf_tail = 0;
}
/*****************************************************************************
* 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)
static void do_console_write(char ch)
{
if ((nr_console < 0) || (nr_console >= NR_CONSOLES))
return;
con.buf[con.buf_tail] = ch;
con.buf_tail = NEXT(con.buf_tail, CON_MAX_LOGBUF);
if (con.buf_head == con.buf_tail) con.buf_head = NEXT(con.buf_head, CON_MAX_LOGBUF);
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)
switch (ch)
{
if (!con->is_full && scr_top > 0)
{
con->crtc_start -= SCR_WIDTH;
case '\n':
con.row ++;
con.col = 0;
if (con.row >= SCR_HEIGHT) {
scroll();
con.row --;
}
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;
}
break;
case '\r':
con.col = 0;
break;
case '\b':
if (con.col == 0) {
if (con.row) con.row --;
con.col = SCR_WIDTH - 1;
}
}
else if (dir == SCR_UP)
{
if (!con->is_full && newest >= scr_top + SCR_SIZE)
{
con->crtc_start += SCR_WIDTH;
else {
con.col --;
}
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;
break;
default:
vga_put_raw(INDEX(con.row, con.col), MAKE_CELL(DEFAULT_CHAR_COLOR, ch));
con.col ++;
if (con.col >= SCR_WIDTH) {
con.col = 0;
con.row ++;
}
}
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);
if (con.row >= SCR_HEIGHT) {
scroll();
con.row --;
}
break;
}
}
/*****************************************************************************
* 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)
void simpleconsole_write(char* buf, int nr)
{
memcpy((void *)(V_MEM_BASE + (dst << 1)),
(void *)(V_MEM_BASE + (src << 1)),
size << 1);
while (nr --) {
do_console_write(*buf ++);
}
set_cursor(INDEX(con.row, con.col));
}
void simpleconsole_transfer(void (*write)(char ch))
{
int i = con.buf_head;
while (i != con.buf_tail) {
write(con.buf[i]);
i = NEXT(i, CON_MAX_LOGBUF);
}
}
void simpleconsole_setcur(int row, int col) {
con.row = max(0, min(row, SCR_HEIGHT-1));
con.col = max(0, min(row, SCR_WIDTH-1));
set_cursor(INDEX(con.row, con.col));
}

View File

@ -19,15 +19,13 @@ int tty_ok = 0;
void tty_write(NTTY *tty, char *buf, int len);
int tty_read(NTTY *tty, char *buf, int len);
static void tty_mouse(TTY *tty);
static void tty_dev_read(TTY *tty);
static void tty_dev_write(TTY *tty);
static void put_key(TTY *tty, u32 key);
NTTY* cur_ntty;
NTTY* ntty_table[NR_CONSOLES];
static void write_default_tty(char ch) {
cur_ntty->write(cur_ntty, ch);
}
inline NTTY* get_tty(const int nr_tty) {
return ntty_table[nr_tty];
}
@ -65,6 +63,7 @@ void init_tty_main()
}
cur_ntty = ntty_table[0];
tty_ok = 1;
simpleconsole_transfer(write_default_tty);
kprintf("TTY initialized\n");
}
@ -97,10 +96,8 @@ void task_tty()
void tty_write(NTTY *tty, char *buf, int len)
{
if (!tty_ok) {
while (--len >= 0)
{
write_serial(*buf++);
}
simpleconsole_write(buf, len);
// while (--len >= 0) write_serial(*buf++);
return;
}
else if (tty->driver_type == 1) {

View File

@ -6,7 +6,7 @@
#include "tty.h"
#include "serialport.h"
static void serialputch(int ch, int *cnt)
static void kprintfputch(int ch, int *cnt)
{
// write_serial(ch);
char _ch = ch;
@ -17,9 +17,8 @@ static void serialputch(int ch, int *cnt)
int vkprintf(const char *fmt, va_list ap)
{
// vprintfmt((void*)kprintfputch, NULL, fmt, ap);
int cnt = 0;
vprintfmt((void *)serialputch, &cnt, fmt, ap);
vprintfmt((void *)kprintfputch, &cnt, fmt, ap);
return 0;
}