⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 kbd.c

📁 一个类linux的dos下开发的操作系统.
💻 C
字号:
/*****************************************************************************
PC KEYBOARD

EXPORTS:
void kbd_irq(void);
void init_kbd(void);
*****************************************************************************/
#include <conio.h> /* KEY_... */
#include <krnl.h>
#include <x86.h> /* inportb(), outportb() */

/* IMPORTS
from STARTUP.ASM */
void halt(void);

/* from VIDEO.C */
extern console_t _vc[];
extern volatile console_t *_curr_vc;

void select_vc(unsigned which_con);
void putch(console_t *con, unsigned char c);

/* from MAIN.C */
void kprintf(const char *fmt, ...);
void wake_up(wait_queue_t *queue);

/* "raw" set 1 scancodes from PC keyboard. Keyboard info here:
http://www.execpc.com/~geezer/osd/kbd */
#define	RAW_LEFT_CTRL	0x1D
#define	RAW_LEFT_SHIFT	0x2A
#define	RAW_CAPS_LOCK	0x3A
#define	RAW_LEFT_ALT	0x38
#define	RAW_RIGHT_ALT	0x38	/* same as left */
#define	RAW_RIGHT_CTRL	0x1D	/* same as left */
#define	RAW_RIGHT_SHIFT	0x36
#define	RAW_SCROLL_LOCK	0x46
#define	RAW_NUM_LOCK	0x45

#define	KBD_BUF_SIZE	512
/*****************************************************************************
*****************************************************************************/
static void reboot(void)
{
	unsigned char temp;

	disable();
/* flush the keyboard controller */
	do
	{
		temp = inportb(0x64);
		if((temp & 0x01) != 0)
		{
			(void)inportb(0x60);
			continue;
		}
	} while((temp & 0x02) != 0);
/* pulse the CPU reset line */
	outportb(0x64, 0xFE);
/* ...and if that didn't work, just halt */
	halt();
}
/*****************************************************************************
	name:	inq
	action:	tries to add data (a byte) to queue
	returns:-1 if queue full
		0  if success
*****************************************************************************/
static int inq(queue_t *q, unsigned char data)
{
	unsigned temp;

	temp = q->in_ptr + 1;
	if(temp >= q->size)
		temp = 0;
/* if in_ptr reaches out_base, the queue is full */
	if(temp == q->out_base)
		return -1;
	q->data[q->in_ptr] = data;
	q->in_ptr = temp;
	return 0;
}
/*****************************************************************************
	name:	write_kbd
	action:	writes data to 8048 keyboard MCU (adr=0x60)
		or 8042 controller MCU (adr=0x64)
*****************************************************************************/
static void write_kbd(unsigned adr, unsigned char data)
{
	unsigned long timeout;
	unsigned char stat;

/* Linux code didn't have a timeout here... */
	for(timeout = 500000L; timeout != 0; timeout--)
	{
		stat = inportb(0x64);
/* loop until 8042 input buffer empty */
		if((stat & 0x02) == 0)
			break;
	}
	if(timeout != 0)
		outportb(adr, data);
}
/*****************************************************************************
	name:	convert
	action:	converts raw scancodes to pseudo-ASCII
	returns:0 if nothing to return, else 8-bit "ASCII" value
*****************************************************************************/
static unsigned short convert(console_t *con, unsigned char code)
{
	static const unsigned char map[] =
	{
/* 00 */0,	0x1B,	'1',	'2',	'3',	'4',	'5',	'6',
/* 08 */'7',	'8',	'9',	'0',	'-',	'=',	'\b',	'\t',
/* 10 */'q',	'w',	'e',	'r',	't',	'y',	'u',	'i',
/* 1Dh is left Ctrl */
/* 18 */'o',	'p',	'[',	']',	'\n',	0,	'a',	's',
/* 20 */'d',	'f',	'g',	'h',	'j',	'k',	'l',	';',
/* 2Ah is left Shift */
/* 28 */'\'',	'`',	0,	'\\',	'z',	'x',	'c',	'v',
/* 36h is right Shift */
/* 30 */'b',	'n',	'm',	',',	'.',	'/',	0,	0,
/* 38h is left Alt, 3Ah is Caps Lock */
/* 38 */0,	' ',	0,	KEY_F1,	KEY_F2,	KEY_F3,	KEY_F4,	KEY_F5,
/* 45h is Num Lock, 46h is Scroll Lock */
/* 40 */KEY_F6,	KEY_F7,	KEY_F8,	KEY_F9,	KEY_F10,0,	0,	KEY_HOME,
/* 48 */KEY_UP,	KEY_PGUP,'-',	KEY_LFT,'5',	KEY_RT,	'+',	KEY_END,
/* 50 */KEY_DN,	KEY_PGDN,KEY_INS,KEY_DEL,0,	0,	0,	KEY_F11,
/* 58 */KEY_F12
	};
	static unsigned short kbd_status;
	unsigned short temp;

/* check for break code (i.e. a key is released) */
	if(code >= 0x80)
	{
		con->saw_break_code = 1;
		code &= 0x7F;
	}
/* the only break codes we're interested in are Shift, Ctrl, Alt */
	if(con->saw_break_code)
	{
		if(code == RAW_LEFT_ALT || code == RAW_RIGHT_ALT)
			kbd_status &= ~KBD_META_ALT;
		else if(code == RAW_LEFT_CTRL || code == RAW_RIGHT_CTRL)
			kbd_status &= ~KBD_META_CTRL;
		else if(code == RAW_LEFT_SHIFT || code == RAW_RIGHT_SHIFT)
			kbd_status &= ~KBD_META_SHIFT;
		con->saw_break_code = 0;
		return 0;
	}
/* it's a make code: check the "meta" keys, as above */
	if(code == RAW_LEFT_ALT || code == RAW_RIGHT_ALT)
	{
		kbd_status |= KBD_META_ALT;
		return 0;
	}
	if(code == RAW_LEFT_CTRL || code == RAW_RIGHT_CTRL)
	{
		kbd_status |= KBD_META_CTRL;
		return 0;
	}
	if(code == RAW_LEFT_SHIFT || code == RAW_RIGHT_SHIFT)
	{
		kbd_status |= KBD_META_SHIFT;
		return 0;
	}
/* Scroll Lock, Num Lock, and Caps Lock set the LEDs. These keys
have on-off (toggle or XOR) action, instead of momentary action */
	if(code == RAW_SCROLL_LOCK)
	{
		kbd_status ^= KBD_META_SCRL;
		goto LEDS;
	}
	if(code == RAW_NUM_LOCK)
	{
		kbd_status ^= KBD_META_NUM;
		goto LEDS;
	}
	if(code == RAW_CAPS_LOCK)
	{
		kbd_status ^= KBD_META_CAPS;
LEDS:		write_kbd(0x60, 0xED);	/* "set LEDs" command */
		temp = 0;
		if(kbd_status & KBD_META_SCRL)
			temp |= 1;
		if(kbd_status & KBD_META_NUM)
			temp |= 2;
		if(kbd_status & KBD_META_CAPS)
			temp |= 4;
		write_kbd(0x60, temp);	/* bottom 3 bits set LEDs */
		return 0;
	}
/* ignore invalid scan codes */
	if(code >= sizeof(map) / sizeof(map[0]))
		return 0;
/* convert raw scancode in code to unshifted ASCII in temp */
	temp = map[code];
/* defective keyboard? non-US keyboard? more than 104 keys? */
	if(temp == 0)
		return temp;
/* handle the three-finger salute */
	if((kbd_status & KBD_META_CTRL) && (kbd_status & KBD_META_ALT) &&
		(temp == KEY_DEL))
	{
		kprintf("\n""\x1B[42;37;1m""*** rebooting!");
		reboot();
	}
/* I really don't know what to do yet with Alt, Ctrl, etc. -- punt */
	return temp;
}
/*****************************************************************************
done:
	8=BS	13=CR
to do:
	4=EOF	7=BEL	9=TAB	10=LF	12=FF	?=CAN (erase line)
*****************************************************************************/
static void do_console(unsigned char key)
{
	unsigned temp;
	queue_t *q;

	q = &_curr_vc->keystrokes;
	if(_curr_vc->unbuffered)
	{
		if(inq(q, key) != 0)
			/* full queue, beep or something */;
/* advance in_base and wake up waiting sys_read()
continuously, with each keystroke */
		q->in_base = q->in_ptr;
		wake_up(&_curr_vc->wait_queue);
	}
	else
	{
/* backspace */
		if(key == 8)
		{
/* if in_ptr equals in_base, the input side of the queue is empty */
			if(q->in_ptr != q->in_base)
			{
				if(q->in_ptr == 0)
					q->in_ptr = q->size - 1;
				else
					q->in_ptr--;
				putch(_curr_vc, key);
				putch(_curr_vc, ' ');
				putch(_curr_vc, key);
			}
		}
		else if(key == '\n')
		{
			if(inq(q, key) || inq(q, '\0'))
				return;/* xxx - should not happen */
			putch(_curr_vc, key);
			putch(_curr_vc, '\r');
/* advance in_base and wake up waiting sys_read()
only when Return is pressed */
			q->in_base = q->in_ptr;
			wake_up(&_curr_vc->wait_queue);
		}
		else if(key >= ' ')
		{
/* need room for 3 bytes (key, and CR and NUL that are stored by Enter) */
			temp = q->in_ptr + 1;
			if(temp >= q->size)
				temp = 0;
/* if in_ptr reaches out_base, the queue is full */
			if(temp == q->out_base)
				return;

			temp = q->in_ptr + 1;
			if(temp >= q->size)
				temp = 0;
			if(temp == q->out_base)
				return;

			temp = q->in_ptr + 1;
			if(temp >= q->size)
				temp = 0;
			if(temp == q->out_base)
				return;

			if(inq(q, key))
				return;/* xxx - should not happen */
			putch(_curr_vc, key);
		}
	}
}
/*****************************************************************************
*****************************************************************************/
void kbd_irq(void)
{
	unsigned short temp;

/* get scancode from port 0x60 */
	temp = inportb(0x60);
/* convert scancode to pseudo-ASCII */
	temp = convert(_curr_vc, temp);
/* if it's F1, F2 etc. switch to the appropriate virtual console */
	switch(temp)
	{
		case KEY_F1:
			temp = 0;
			goto SWITCH_VC;
		case KEY_F2:
			temp = 1;
			goto SWITCH_VC;
		case KEY_F3:
			temp = 2;
			goto SWITCH_VC;
		case KEY_F4:
			temp = 3;
			goto SWITCH_VC;
		case KEY_F5:
			temp = 4;
			goto SWITCH_VC;
		case KEY_F6:
			temp = 5;
			goto SWITCH_VC;
		case KEY_F7:
			temp = 6;
			goto SWITCH_VC;
		case KEY_F8:
			temp = 7;
			goto SWITCH_VC;
		case KEY_F9:
			temp = 8;
			goto SWITCH_VC;
		case KEY_F10:
			temp = 9;
			goto SWITCH_VC;
		case KEY_F11:
			temp = 10;
			goto SWITCH_VC;
		case KEY_F12:
			temp = 11;
SWITCH_VC:
			select_vc(temp);
			break;
/* convert() ate it */
		case 0:
			break;
		default:
			do_console(temp);
			break;
	}
}
/*****************************************************************************
*****************************************************************************/
DISCARDABLE_CODE(void init_kbd(void))
{
	static unsigned char buffers[KBD_BUF_SIZE * MAX_VC];
	int temp;

	for(temp = 0; temp < MAX_VC; temp++)
	{
		_vc[temp].keystrokes.data = buffers + KBD_BUF_SIZE * temp;
		_vc[temp].keystrokes.size = KBD_BUF_SIZE;
	}
	kprintf("init_kbd: %u buffers, %u bytes each\n",
		MAX_VC, KBD_BUF_SIZE);
}

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -