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

📄 kbdriver.c

📁 从网上下载的一个自己编写的简单的操作系统源代码,对底层了解很有好处的
💻 C
📖 第 1 页 / 共 2 页
字号:
/*****************************************************************************
Keyboard driver/interrupt handler demo code.

This code is public domain (no copyright).
You can do whatever you want with it.

Scancode set 3 is very nice:
- one-byte make code for each key
- break code is the make code preceded by F0h
- each key can be programmed individually to repeat or not,
  and to generate a break code or not
Unfortunately, not all keyboards support set 3.

Scancodes set 2 and 1 are crap:
- keys have scancodes of different lengths: 01 for Esc,
  E038 for right Alt, and E11D45E19DC5 for Pause in set 1
- some keys produce different scancodes depending on
  the internal num lock state of the keyboard:
  Insert, Home, PageUp, Delete, End, PageDown,
  the arrow keys, and the Windows and Menu keys
- the 8042 keyboard controller chip does optional translation
  of set 2 scancodes (AT) to set 1 (XT), so that's one more
  thing to worry about

To give you an idea of what a mess this is,
look at the set 2 scancodes for the Insert key:

8042		internal
XT-to-AT	Num Lock	make		repeat		break
conversion	state		code		code		code
----------	--------	-----		------		-----
off		off		E070		E070		E0F070
off		ON		E012E070	E070		E0F070E0F012
ON		off		E052		E052		E0D2
ON		ON		E02AE052	E052		E0D2E0AA

Naturally, only set 2 seems to be supported by all keyboards.

xxx - trouble with this code: when keyboard internal num lock is on,
the E0AA or E0F012 appears BEFORE the NEXT MAKE code,
instead of AFTER the CURRENT BREAK code
*****************************************************************************/
#include <arch.h> /* inportb(), outportb() */

/* this will change if you reprogram the 8259 chips to route
IRQs to non-reserved INTs (a pmode OS should do this) */
#define	KBD_VECT_NUM	9




#define	INTERRUPT			/* nothing */

 
/*----------------------------------------------------------------------------
CIRCULAR QUEUES
----------------------------------------------------------------------------*/
typedef struct
{
	unsigned char *data;
	unsigned size, in_ptr, out_ptr;
} queue_t;
/*****************************************************************************
*****************************************************************************/
static int inq(queue_t *q, unsigned data)
{
	unsigned temp;

	temp = q->in_ptr + 1;
	if(temp >= q->size)
		temp = 0;
/* if in_ptr reaches out_ptr, the queue is full */
	if(temp == q->out_ptr)
		return -1;
	q->data[q->in_ptr] = data;
	q->in_ptr = temp;
	return 0;
}
/*****************************************************************************
*****************************************************************************/
static int deq(queue_t *q, unsigned char *data)
{
/* if out_ptr reaches in_ptr, the queue is empty */
	if(q->out_ptr == q->in_ptr)
		return -1;
	*data = q->data[q->out_ptr++];
	if(q->out_ptr >= q->size)
		q->out_ptr = 0;
	return 0;
}
/*****************************************************************************
*****************************************************************************/
static int empty(queue_t *q)
{
	return q->out_ptr == q->in_ptr;
}
/*----------------------------------------------------------------------------
LOW-LEVEL KEYBOARD DRIVER
----------------------------------------------------------------------------*/
#define	BUF_SIZE	64

static unsigned char g_kbd_buf[BUF_SIZE];
static queue_t g_queue =
{
	g_kbd_buf, BUF_SIZE, 0, 0
};
/*****************************************************************************
*****************************************************************************/
void INTERRUPT kbd_irq(void)
{
	unsigned scan_code;

/* read I/O port 60h to reset interrupt at 8042 keyboard controller chip */
	scan_code = readchar();
/* put scancode in queue */
	(void)inq(&g_queue, scan_code);
/* reset interrupt at 8259 interrupt controller chip */
	outb_p(0x20, 0x20);
}
/*****************************************************************************
*****************************************************************************/

/*****************************************************************************
*****************************************************************************/
static void write_kbd(unsigned adr, unsigned data)
{
	unsigned long timeout;
	unsigned stat;

	for(timeout = 500000L; timeout != 0; timeout--)
	{
		stat = inb_p(0x64);
/* loop until 8042 input buffer empty */
		if((stat & 0x02) == 0)
			break;
	}
	if(timeout == 0)
	{
		kprintf("write_kbd: timeout\n");
		return;
	}
	outb_p(adr, data);
}
/*****************************************************************************
*****************************************************************************/
#if 0
static int read_kbd(void)
{
	unsigned long timeout;
	unsigned stat, data;

	for(timeout = 500000L; timeout != 0; timeout--)
	{
		stat = inb_p(0x64);
/* loop until 8042 output buffer full */
		if(stat & 0x01)
		{
			data = inb_p(0x60);
/* loop if parity error or receive timeout */
			if((stat & 0xC0) == 0)
				return data;
		}
	}
/*	kprintf("read_kbd: timeout\n"); */
	return -1;
}


static int write_kbd_await_ack(unsigned val)
{
	int got;

	write_kbd(0x60, val);
	got = read_kbd();
	if(got != 0xFA)
	{
		kprintf("write_kbd_await_ack: expected (0xFA)");
		newline();
		return -1;
	}
	return 0;
}
/*****************************************************************************
*****************************************************************************/

static int init_kbd(unsigned ss, unsigned typematic, unsigned xlat)
{
//	kprintf("flushing keyboard output\n");
	while(read_kbd() != -1)
		/* nothing */;
/* disable keyboard before programming it */
	//kprintf("disabling keyboard controller\n");
	if(write_kbd_await_ack(0xF5) != 0)
		return -1;
/* disable PS/2 mouse, set SYS bit, and Enable Keyboard Interrupt... */
	write_kbd(0x64, 0x60);
/* ...and either disable or enable AT-to-XT keystroke conversion */
	write_kbd(0x60, xlat ? 0x65 : 0x25);
/* program desired scancode set */
	//kprintf("programming scancode set "); newline();
	if(write_kbd_await_ack(0xF0) != 0)
		//return -1;
	if(write_kbd_await_ack(ss) != 0)
		return -1;
/* we want all keys to return both a make code (when pressed)
and a break code (when released -- scancode set 3 only) */
	if(ss == 3)
	{
		//kprintf("making all keys make-break");
		if(write_kbd_await_ack(0xFA) != 0)
			return -1;
	}
/* set typematic delay and rate */
	//kprintf("setting fast typematic mode");
	if(write_kbd_await_ack(0xF3) != 0)
		return -1;
	if(write_kbd_await_ack(typematic) != 0)
		return -1;
/* enable keyboard */
	//kprintf("enabling keyboard controller\n");
	if(write_kbd_await_ack(0xF4) != 0)
		return -1;
	return 0;
}
#endif

/*----------------------------------------------------------------------------
SCANCODE CONVERSION
----------------------------------------------------------------------------*/
/* "ASCII" values for non-ASCII keys. All of these are user-defined.
function keys: */
#define	KEY_F1		0x80
#define	KEY_F2		(KEY_F1 + 1)
#define	KEY_F3		(KEY_F2 + 1)
#define	KEY_F4		(KEY_F3 + 1)
#define	KEY_F5		(KEY_F4 + 1)
#define	KEY_F6		(KEY_F5 + 1)
#define	KEY_F7		(KEY_F6 + 1)
#define	KEY_F8		(KEY_F7 + 1)
#define	KEY_F9		(KEY_F8 + 1)
#define	KEY_F10		(KEY_F9 + 1)
#define	KEY_F11		(KEY_F10 + 1)
#define	KEY_F12		(KEY_F11 + 1)
/* cursor keys */
#define	KEY_INS		0x90
#define	KEY_DEL		(KEY_INS + 1)
#define	KEY_HOME	(KEY_DEL + 1)
#define	KEY_END		(KEY_HOME + 1)
#define	KEY_PGUP	(KEY_END + 1)
#define	KEY_PGDN	(KEY_PGUP + 1)
#define	KEY_LFT		(KEY_PGDN + 1)
#define	KEY_UP		(KEY_LFT + 1)
#define	KEY_DN		(KEY_UP + 1)
#define	KEY_RT		(KEY_DN + 1)
/* print screen/sys rq and pause/break */
#define	KEY_PRNT	(KEY_RT + 1)
#define	KEY_PAUSE	(KEY_PRNT + 1)
/* these return a value but they could also act as additional meta keys */
#define	KEY_LWIN	(KEY_PAUSE + 1)
#define	KEY_RWIN	(KEY_LWIN + 1)
#define	KEY_MENU	(KEY_RWIN + 1)

/* "meta bits"
0x0100 is reserved for non-ASCII keys, so start with 0x200 */
#define	KBD_META_ALT	0x0200	/* Alt is pressed */
#define	KBD_META_CTRL	0x0400	/* Ctrl is pressed */
#define	KBD_META_SHIFT	0x0800	/* Shift is pressed */
#define	KBD_META_ANY	(KBD_META_ALT | KBD_META_CTRL | KBD_META_SHIFT)
#define	KBD_META_CAPS	0x1000	/* CapsLock is on */
#define	KBD_META_NUM	0x2000	/* NumLock is on */
#define	KBD_META_SCRL	0x4000	/* ScrollLock is on */
/*****************************************************************************
*****************************************************************************/
#define	RAW1_LEFT_CTRL		0x1D
#define	RAW1_LEFT_SHIFT		0x2A
#define	RAW1_CAPS_LOCK		0x3A
#define	RAW1_LEFT_ALT		0x38
#define	RAW1_RIGHT_ALT		0x38	/* same as left */
#define	RAW1_RIGHT_CTRL		0x1D	/* same as left */
#define	RAW1_RIGHT_SHIFT	0x36
#define	RAW1_SCROLL_LOCK	0x46
#define	RAW1_NUM_LOCK		0x45
#define	RAW1_DEL		0x53

static int set1_scancode_to_ascii(unsigned 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 const unsigned char shift_map[] =
	{
/* 00 */0,	0x1B,	'!',	'@',	'#',	'$',	'%',	'^',
/* 08 */'&',	'*',	'(',	')',	'_',	'+',	'\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 saw_break_code, kbd_status;
/**/
	unsigned temp;

/* check for break code (i.e. a key is released) */
	if(code >= 0x80)
	{
		saw_break_code = 1;
		code &= 0x7F;
	}
/* the only break codes we're interested in are Shift, Ctrl, Alt */
	if(saw_break_code)
	{
		if(code == RAW1_LEFT_ALT || code == RAW1_RIGHT_ALT)
			kbd_status &= ~KBD_META_ALT;
		else if(code == RAW1_LEFT_CTRL || code == RAW1_RIGHT_CTRL)
			kbd_status &= ~KBD_META_CTRL;
		else if(code == RAW1_LEFT_SHIFT || code == RAW1_RIGHT_SHIFT)
			kbd_status &= ~KBD_META_SHIFT;

⌨️ 快捷键说明

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