冬天OS(十七):TTY 框架搭建

--------------------------------------------------------

TTY 框架搭建

--------------------------------------------------------

从这一篇章开始,开始讨论 TTY ,而 TTY 涉及到 "视频" 的操作,因此先要了解 VGA ... 

 

一,让光标出现在显示字符的后面

运行:

可以看到光标出现在打印字符的后面!

 

二,搭建 TTY 框架
这次的框架搭建虽然有点麻烦,但是机制并不复杂,let us do it!
 

// ----------------------------
// <console.c>
// Jack Zheng 12.1
// ----------------------------
#include "type.h"
#include "const.h"
#include "protect.h"
#include "string.h"
#include "proc.h"
#include "tty.h"
#include "console.h"
#include "global.h"
#include "keyboard.h"
#include "proto.h"

/* 本文件内函数声明 */
PRIVATE void	set_cursor(unsigned int position);

PUBLIC void out_char(CONSOLE* p_con, char ch)
{
	t_8* p_vmem = (t_8*)(V_MEM_BASE + disp_pos);

	*p_vmem++ = ch;
	*p_vmem++ = DEFAULT_CHAR_COLOR;
	disp_pos += 2;

	set_cursor(disp_pos/2);
}

PUBLIC t_bool is_current_console(CONSOLE* p_con)
{
	return (p_con == &console_table[nr_current_console]);
}

PRIVATE void set_cursor(unsigned int position)
{
	disable_int();
	out_byte(CRTC_ADDR_REG, CRTC_DATA_IDX_CURSOR_H);
	out_byte(CRTC_DATA_REG, (position >> 8) & 0xFF);
	out_byte(CRTC_ADDR_REG, CRTC_DATA_IDX_CURSOR_L);
	out_byte(CRTC_DATA_REG, position & 0xFF);
	enable_int();
}
// ----------------------------
// <tty.c>
// Jack Zheng 11.30
// ----------------------------
#include "type.h"
#include "const.h"
#include "protect.h"
#include "string.h"
#include "proc.h"
#include "tty.h"
#include "console.h"
#include "global.h"
#include "keyboard.h"
#include "proto.h"

#define TTY_FIRST	(tty_table)
#define TTY_END		(tty_table + NR_CONSOLES)

/* 本文件内函数声明 */
PRIVATE void	init_tty(TTY* p_tty);
PRIVATE void	tty_do_read(TTY* p_tty);
PRIVATE void	tty_do_write(TTY* p_tty);

PUBLIC void task_tty()
{
	TTY*	p_tty;

	for (p_tty=TTY_FIRST;p_tty<TTY_END;p_tty++) {
		init_tty(p_tty);
	}

	nr_current_console = 0;

	while (1) {
		for (p_tty=TTY_FIRST;p_tty<TTY_END;p_tty++) {
			tty_do_read(p_tty);
			tty_do_write(p_tty);
		}
	}
}

PRIVATE void init_tty(TTY* p_tty)
{
	p_tty->inbuf_count = 0;
	p_tty->p_inbuf_head = p_tty->p_inbuf_tail = p_tty->in_buf;

	int nr_tty = p_tty - tty_table;
	p_tty->p_console = console_table + nr_tty;
}

PUBLIC void in_process(TTY* p_tty, t_32 key)
{
	if (!(key & FLAG_EXT)) {
		if (p_tty->inbuf_count < TTY_IN_BYTES) {
			*(p_tty->p_inbuf_head) = key;
			p_tty->p_inbuf_head++;
			if (p_tty->p_inbuf_head == p_tty->in_buf + TTY_IN_BYTES) {
				p_tty->p_inbuf_head = p_tty->in_buf;
			}
			p_tty->inbuf_count++;
		}
	}
	else {
		int raw_code = key & MASK_RAW;
		switch(raw_code) {
		case UP:
			if ((key & FLAG_SHIFT_L) || (key & FLAG_SHIFT_R)) {	/* Shift + Up */
				disable_int();
				out_byte(CRTC_ADDR_REG, CRTC_DATA_IDX_START_ADDR_H);
				out_byte(CRTC_DATA_REG, ((80*15) >> 8) & 0xFF);
				out_byte(CRTC_ADDR_REG, CRTC_DATA_IDX_START_ADDR_L);
				out_byte(CRTC_DATA_REG, (80*15) & 0xFF);
				enable_int();
			}
			break;
		case DOWN:
			if ((key & FLAG_SHIFT_L) || (key & FLAG_SHIFT_R)) {	/* Shift + Down */
			}
			break;
		default:
			break;
		}
	}
}

PRIVATE void tty_do_read(TTY* p_tty)
{
	if (is_current_console(p_tty->p_console)) {
		keyboard_read(p_tty);
	}
}

PRIVATE void tty_do_write(TTY* p_tty)
{
	if (p_tty->inbuf_count) {
		char ch = *(p_tty->p_inbuf_tail);
		p_tty->p_inbuf_tail++;
		if (p_tty->p_inbuf_tail == p_tty->in_buf + TTY_IN_BYTES) {
			p_tty->p_inbuf_tail = p_tty->in_buf;
		}
		p_tty->inbuf_count--;

		out_char(p_tty->p_console, ch);
	}
}
// ----------------------------
// <gloabl.h>
// Jack Zheng 11.27
// ----------------------------
#ifndef _TINIX_GLOBAL_H_
#define _TINIX_GLOBAL_H_

// these variables will real define in global.c!
#ifdef	GLOBAL_VARIABLES_HERE
#undef 	EXTERN
#define	EXTERN
#endif

EXTERN	int		disp_pos;
EXTERN	t_32		k_reenter;
EXTERN	int		ticks;
EXTERN	PROCESS*	p_proc_ready;
EXTERN	TSS		tss;

/* gdt & idt */
EXTERN	t_8		gdt_ptr[6];
EXTERN	DESCRIPTOR	gdt[GDT_SIZE];
EXTERN	t_8		idt_ptr[6];
EXTERN	GATE		idt[IDT_SIZE];

/* task... */
extern	PROCESS		proc_table[NR_TASKS];
extern	char		task_stack[STACK_SIZE_TOTAL];
extern	TASK		task_table[NR_TASKS];

/* tty and console*/
#ifndef _TINIX_TTY_H_
#define TTY_IN_BYTES	256	/* tty input queue size */
typedef struct s_tty
{
	t_32	in_buf[TTY_IN_BYTES];	/* TTY 输入缓冲区 */
	t_32*	p_inbuf_head;		/* 指向缓冲区中下一个空闲位置 */
	t_32*	p_inbuf_tail;		/* 指向键盘任务应处理的键值 */
	int	inbuf_count;		/* 缓冲区中已经填充了多少 */

	struct s_console *	p_console;
}TTY;
#endif
#ifndef _TINIX_CONSOLE_H_
typedef struct s_console
{
	//struct s_tty*	p_tty;
	unsigned int	current_start_addr;	/* 当前显示到了什么位置   */
	unsigned int	original_addr;		/* 当前控制台对应显存位置 */
	unsigned int	v_mem_limit;		/* 当前控制台占的显存大小 */
	unsigned int	cursor;			/* 当前光标位置 */
}CONSOLE;
#endif
EXTERN	int		nr_current_console;
extern	TTY		tty_table[];
extern	CONSOLE		console_table[];

/* hard interrupt handler table */
extern	t_pf_irq_handler	irq_table[NR_IRQ];

/* syscall function table */
extern	t_sys_call	sys_call_table[NR_SYS_CALL];

#endif

运行:

 

接下来我们捋一下键盘和 TTY 的配合:


1,首先键盘中断函数 keyboard_handler 从键盘端口里取得扫描码放入 kb_in 中存储:


typedef struct s_kb {
    char*    p_head;            /* 指向缓冲区中下一个空闲位置 */
    char*    p_tail;            /* 指向键盘任务应处理的字节 */
    int    count;            /* 缓冲区中共有多少字节 */
    char    buf[KB_IN_BYTES];    /* 缓冲区 */
}KB_INPUT;


2,然后 TTY_TASK 循环调用函数 keyboard_read 读取 kb_in ,并将 kb_in 中扫描码解析成字符交给 in_process!


3,in_process 将解析到的字符交给传递给它的 TTY,TTY 有个数据结构 struct TTY 用来保存交给自己的字符:


typedef struct s_tty
{
    t_32    in_buf[TTY_IN_BYTES];    /* TTY 输入缓冲区 */
    t_32*    p_inbuf_head;        /* 指向缓冲区中下一个空闲位置 */
    t_32*    p_inbuf_tail;        /* 指向键盘任务应处理的键值 */
    int    inbuf_count;        /* 缓冲区中已经填充了多少 */

    struct s_console *    p_console;
}TTY;


4,最后 tty_do_write 函数将 TTY 缓冲区的字符写到 TTY 对应的 Console 上!

 

这里有两个数结构 kb_in 和 in_buf ,kb_in 保存从键盘缓冲区接收到的扫描码,然后被 keyboard_read 解析成字符送给 in_buf !

 

OK,TTY 的框架已经搭建起来了,下一节我们就实现一个多 TTY 的内核!

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

sssnial-jz

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值