添加缓冲区


include\linux下添加一个tty.h,我们定义了一个队列结构体tty_queue,定义了一个tty_struct结构体,里面有三个队列read_q、write_q、secondary还有一个函数指针,剩下的就是一些对队列的操作。

#ifndef TTY_H
#define TTY_H

#define TTY_BUF_SIZE 1024


struct tty_queue {
	unsigned long data;
	unsigned long head;
	unsigned long tail;
	struct task_struct * proc_list;
	char buf[TTY_BUF_SIZE];
};
struct tty_struct {
	void (*write)(struct tty_struct * tty);
	struct tty_queue read_q;
	struct tty_queue write_q;
	struct tty_queue secondary;
	};
#define INC(a) ((a) = ((a)+1) & (TTY_BUF_SIZE-1))
#define DEC(a) ((a) = ((a)-1) & (TTY_BUF_SIZE-1))
#define EMPTY(a) ((a).head == (a).tail)
#define CHARS(a) (((a).head-(a).tail)&(TTY_BUF_SIZE-1))
#define GETCH(queue,c) \
(void)({c=(queue).buf[(queue).tail];INC((queue).tail);})
#define PUTCH(c,queue) \
(void)({(queue).buf[(queue).head]=(c);INC((queue).head);})

extern struct tty_struct tty_table[];

#endif

key_board.c中定义一个tty_table数组,类型是tty_struct,其实在这里直接用一个tty_struct类型的变量会好一些,不过为了和linux统一也为了以后扩展方便就定义了一个数组。

put_queue是将扫描码如队列

#include <linux/tty.h>


extern void con_write(struct tty_struct * tty);
struct tty_struct tty_table[] = {
	{

		con_write,
		{0,0,0,0,""},		/* console read-queue */
		{0,0,0,0,""},		/* console write-queue */
		{0,0,0,0,""}		/* console secondary queue */
	}
};

void put_queue(char scan_code)
{

	unsigned long head;
	head=tty_table[0].read_q.head;
	tty_table[0].read_q.buf[head] = scan_code;
		head++;
	
	if(head>TTY_BUF_SIZE-1)
		head = 0;
	if(head != tty_table[0].read_q.tail)//如果头指针不等于尾指针
		tty_table[0].read_q.head=head;

}

console.c的改动比较大,但是很简单,首先我们先定义了一堆和屏幕、显存相关的变量,然后在con_init中对这些变量初始化。con_write函数的主要工作是解析写队列中的扫描码,转化为相应的字符并显示在屏幕上,当然目前的con_write并不完善。do_tty_interrupt中调用了copy_to_cooked,copy_to_cooked将读队列中的扫描码放到写队列中,然后调用tty->write(tty)


#include <linux/head.h>
#include <asm/system.h>
#include <asm/io.h>
#include <linux/tty.h>

static unsigned char	video_type;	//使用的显示类型
static unsigned long	video_num_columns;	//屏幕文本列数
static unsigned long	video_num_lines;	//屏幕文本行数
static unsigned long	video_size_row;		//屏幕每行使用的字节数

static unsigned long	video_mem_start;	//显示内存起始地址
static unsigned long	video_mem_end;		//显示内存结束地址
static unsigned short	video_port_reg;		//显示控制索引寄存器端口
static unsigned short	video_port_val;		//显示控制数据寄存器端口
static unsigned short	video_erase_char;	//擦除字符属性及字符(0x0720)


static unsigned long	origin;		//一屏的起始内存地址
static unsigned long	scr_end;	//一屏的末端内存地址
static unsigned long	pos;      //当前光标对应显示内存的位置
static unsigned long	x,y;			//当前光标的位置
static unsigned long	top,bottom;//滚动时顶行行号和底行行号
static unsigned char	attr=0x0f;//字符属性(黑底白字,字符高亮)高四位:背景(高亮/R/G/B);低四位:前景(高亮/R/G/B)
#define VIDEO_TYPE_EGAC		0x21	// EGA/VGA 彩色模式


#define ORIG_X			0//初始光标列号
#define ORIG_Y			0//初始光标行号
#define ORIG_VIDEO_COLS 	(80)//字符列数
#define ORIG_VIDEO_LINES	(25)//字符行数

extern void keyboard_interrupt(void);	
//设置光标的位置变量x,y和光标在显存中对应的位置pos
static inline void gotoxy(unsigned 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;
	//origin是一屏的起始内存地址,video_size_row是每行使用的字节数,1列用两个字节表示所以x<<1
	pos=origin + y*video_size_row + (x<<1);
}

void con_init(void)
{
	register unsigned char a;
	char *display_ptr;

	video_num_columns = ORIG_VIDEO_COLS;//字符列数,80
	video_size_row = video_num_columns * 2;//屏幕每行使用的字节数
	video_num_lines = ORIG_VIDEO_LINES;//字符列数,25
	video_erase_char = 0x0720;//擦除字符属性及字符
	
	
	video_mem_start = 0xb8000;//显示内存起始地址
	video_port_reg	= 0x3d4;//显示控制索引寄存器端口
	video_port_val	= 0x3d5;//显示控制数据寄存器端口
	video_type = VIDEO_TYPE_EGAC;// EGA/VGA 彩色模式
	video_mem_end = 0xbc000;//显示内存结束地址

		
	origin	= video_mem_start;//一屏的起始内存地址
	scr_end	= video_mem_start + video_num_lines * video_size_row;//一屏的末端内存地址
	top	= 0;//滚动时顶行行号
	bottom	= video_num_lines;//滚动时底行行号
	//设置光标位置
	gotoxy(ORIG_X,ORIG_Y);
	//注册键盘中断函数
	set_trap_gate(0x21,&keyboard_interrupt);
	//下面操作是打开键盘中断
	outb_p(inb_p(0x21)&0xfd,0x21);
	a=inb_p(0x61);
	outb_p(a|0x80,0x61);
	outb(a,0x61);

}
//擦除光标前一个字符(用空格代替),并设置pos和x变量
static void del(void)
{
	if (x) {//如果光标没有在0列
		pos -= 2;//pos后退2个字节(一个字符对应两个字节)
		x--;//光标位置x减1
		*(unsigned short *)pos = video_erase_char;//擦除pos处字符
	}
}
//光标调回第一列(0列)
static void cr(void)
{
	pos -= x<<1;//因为一列占两个字节,所以减去x<<1
	x=0;//x清零
}
//光标位置下移一行
static void lf(void)
{
	if (y+1<bottom) {//如果光标没有在最后一行上
		y++;//光标行坐标加1
		pos += video_size_row;//video_size_row为每行使用的字节数,相当于加一行
		return;
	}
	//scrup();
}
//根据光标对应显存位置pos,设置显示控制器光标的显示位置
static inline void set_cursor(void)
{
	cli();//关中断
	//向显示控制索引寄存器端口(0x3d4)写14
	outb_p(14, video_port_reg);//选择数据寄存器r14
	//向显示控制数据寄存器端口(0x3d5),写入光标当前位置的高字节
	outb_p(0xff&((pos-video_mem_start)>>9), video_port_val);
	//向显示控制索引寄存器端口(0x3d4)写14
	outb_p(15, video_port_reg);//选择数据寄存器r15
	//向显示控制数据寄存器端口(0x3d5),写入光标当前位置的低字节
	outb_p(0xff&((pos-video_mem_start)>>1), video_port_val);
	sti();//开中断
}
void con_write(struct tty_struct * tty)
{
	int nr;
	char c;

	nr = CHARS(tty->write_q);
	while (nr--) {
		GETCH(tty->write_q,c);
	
		if (c>31 && c<127) {
			(*(char *)pos++) = c;
			(*(char *)pos++) = attr;
			x++;
		}
		else if (c==127) {
		del();
		}
		else if (c==13){
			cr();
			lf();
		}
	}
	set_cursor();
}
void copy_to_cooked(struct tty_struct * tty)
{
	signed char c;
	if(!EMPTY(tty->read_q) ){
		GETCH(tty->read_q,c);
		PUTCH(c,tty->write_q);
		tty->write(tty);
	}
}

void do_tty_interrupt(int tty)
{
	copy_to_cooked(tty_table+tty);
}


system.h中添加

#define cli() __asm__ ("cli"::)


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值