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

📄 kbd.c

📁 Linux0.01设备驱动程序 最精简的linux代码 适合操作系统入门
💻 C
📖 第 1 页 / 共 2 页
字号:
/*****************************************************************************
	kbd.c - PC keyboard demo code/driver for OS
	Christopher Giese <geezer[AT]execpc.com>

	Release date 9/2/99. Distribute freely. ABSOLUTELY NO WARRANTY.
	Compile with DJGPP or Turbo C or possibly Borland C.

Changes/fixes:
	- got numeric keypad and NumLock working
	- slightly different scancode-to-ASCII conversion logic
	- created #defines for raw scancode values
	- different ordering of events during keyboard and controller init
Sources:
	- PORTS.A of Ralf Brown's interrupt list collection
	- repairfaq.org keyboard FAQ at
	    http://www.repairfaq.org/filipg/LINK/PORTS/F_Keyboard_FAQ.html
	- Linux source code
Test hardware:
	- New Samsung KB3T001SAXAA 104-key keyboard
	- Old Maxi 2186035-00-21 101-key keyboard
To do:
	- turn off auto-repeat for lock keys?

	- ioctl()s (functions, for now -- use interrupts?) to
	  - set make/break or make-only for each key
	  - set typematic mode or not for each key
	  - set typematic rate and delay

	- Unicode/UTF-8
	- Alt+number entered on numeric keypad == scancode, like DOS?
*****************************************************************************/
#include	<stdio.h>	/* printf() */
/* union REGS, int86(), inportb(), outportb(), getvect(), setvect() */
#include	<dos.h>

#if 1
#define	DEBUG(X)	X
#else
#define	DEBUG(X)
#endif

/* quick and dirty begin/end critical section... */
#define	critb()		(disable(), 0)
#define	crite(X)	enable()

/* geezer's Portable Interrupt Macros (tm) */
#if defined(__TURBOC__)
/* getvect(), setvect() in dos.h */

/* from Turbo C++ getvect() help */
#ifdef	__cplusplus
#define	__CPPARGS	...
#else
#define	__CPPARGS
#endif

typedef void interrupt(*vector)(__CPPARGS);
#define SAVE_VECT(Num,Vec)	Vec=getvect(Num)
#define	SET_VECT(Num,Fn)	setvect(Num, Fn)
#define	RESTORE_VECT(Num,Vec)	setvect(Num, Vec)

#elif defined(__DJGPP__)
#include	<dpmi.h>	/* _go32_dpmi_... */
#include	<go32.h>	/* _my_cs() */

#define	interrupt
#define	__CPPARGS
typedef _go32_dpmi_seginfo vector;
#define	SAVE_VECT(Num,Vec)	\
	_go32_dpmi_get_protected_mode_interrupt_vector(Num, &Vec)
#define	SET_VECT(Num,Fn)					\
	{	_go32_dpmi_seginfo NewVector;			\
								\
		NewVector.pm_selector=_my_cs();			\
		NewVector.pm_offset=(unsigned long)Fn;		\
		_go32_dpmi_allocate_iret_wrapper(&NewVector);	\
		_go32_dpmi_set_protected_mode_interrupt_vector	\
			(Num, &NewVector); }
#define	RESTORE_VECT(Num,Vec)	\
	_go32_dpmi_set_protected_mode_interrupt_vector(Num, &Vec)

#else
#error Not Turbo C nor DJGPP, sorry.
#endif

/* Info from file PORTS.A of Ralf Brown's interrupt list collection
   I/O addresses of 8042 keyboard controller on PC motherboard */
#define	_KBD_STAT_REG		0x64
#define	_KBD_CMD_REG		0x64
#define	_KBD_DATA_REG		0x60

/* 8042 controller commands (write to 0x64; Table P0401 in PORTS.A) */
#define	_KBD_CCMD_WRCMDB	0x60	/* write "Command Byte" */
#define	_KBD_CCMD_TEST1		0xAA	/* controller self-test */
#define	_KBD_CCMD_TEST2		0xAB	/* interface test */
#define	_KBD_CCMD_ENABLE	0xAE
/* Linux enables A20 by writing _KBD_CCMD_WROPRT to 0x64 and 0xDF to 0x60 */
#define	_KBD_CCMD_WROPRT	0xD1	/* write 8042 output port */

/* keyboard commands (write to 0x60; Table P0386 in PORTS.A) */
#define	_KBD_KCMD_LEDS		0xED	/* set LEDs */
#define	_KBD_KCMD_SCSET		0xF0	/* get/set scancode set */
#define	_KBD_KCMD_TYPEM		0xF3	/* set auto-repeat settings */
#define	_KBD_KCMD_EN		0xF4	/* enable scanning */
#define	_KBD_KCMD_DIS		0xF5	/* disable scanning */
#define	_KBD_KCMD_TMB		0xFA	/* all keys typematic/make-break */
#define	_KBD_KCMD_RESET		0xFF	/* full reset of 8048 + self-test */

/* bits for "Command Byte" (confusing name; Table P0404 in PORTS.A).
Bit names are from Linux source.
				0x80	reserved */
#define	_KBD_CB_KCC		0x40	/* do AT-to-XT scancode translation */
#define	_KBD_CB_DMS		0x20	/* force mouse clock low */
/*				0x10	disable keyboard clock (?)
				0x08	ignore keyboard lock switch (reserved?) */
#define	_KBD_CB_SYS		0x04	/* system flag (?) */
/*				0x02	reserved (enable PS/2 mouse IRQ12?) */
#define	_KBD_CB_EKI		0x01	/* enable IRQ1 for _KBD_STAT_OBF */
/* Linux also sets _KBD_CB_KCC here: */
#define	_KBD_CB_INIT		(_KBD_CB_DMS | _KBD_CB_SYS | _KBD_CB_EKI)


/* status bits read from 0x64 (Table P0398 in PORTS.A) */
#define	_KBD_STAT_PERR		0x80	/* parity error in data from kbd */
#define	_KBD_STAT_GTO		0x40	/* receive timeout */
/*				0x20	xmit timeout
				0x10	keyboard locked
				0x08
	=1 data written to input register is command (PORT 0064h)
	=0 data written to input register is data (PORT 0060h)
				0x04
	system flag status: 0=power up or reset	 1=self-test OK */
#define	_KBD_STAT_IBF		0x02	/* input buffer full (data for kbd) */
#define	_KBD_STAT_OBF		0x01	/* output bffr full (data for host) */

/* #defines from here down can be brought out to a separate .h file,
for use by programs that talk to the keyboard */

/* "bucky bits" */
#define	KBD_BUCKY_ALT		0x8000	/* Alt is pressed */
#define	KBD_BUCKY_CTRL		0x4000	/* Ctrl is pressed */
#define	KBD_BUCKY_SHIFT		0x2000	/* Shift is pressed */
#define	KBD_BUCKY_ANY		\
			(KBD_BUCKY_ALT | KBD_BUCKY_CTRL | KBD_BUCKY_SHIFT)
#define	KBD_BUCKY_CAPS		0x1000	/* CapsLock is on */
#define	KBD_BUCKY_NUM		0x0800	/* NumLock is on */
#define	KBD_BUCKY_SCRL		0x0400	/* ScrollLock is on */

/* "raw" set 3 scancodes */
#define	RK_LEFT_CTRL	0x11
#define	RK_LEFT_SHIFT	0x12
#define	RK_CAPS_LOCK	0x14
#define	RK_LEFT_ALT	0x19
#define	RK_RIGHT_ALT	0x39
#define	RK_RIGHT_CTRL	0x58
#define	RK_RIGHT_SHIFT	0x59
#define	RK_SCROLL_LOCK	0x5F
#define	RK_NUM_LOCK	0x76
#define	RK_END_1	0x69	/* End/1 on numeric keypad */
#define	RK_BREAK_CODE	0xF0

/* "ASCII" values for non-ASCII keys. All of these are user-defined.
Function keys: */
#define	K_F1		0x100
#define	K_F2		(K_F1 + 1)
#define	K_F3		(K_F2 + 1)
#define	K_F4		(K_F3 + 1)
#define	K_F5		(K_F4 + 1)
#define	K_F6		(K_F5 + 1)
#define	K_F7		(K_F6 + 1)
#define	K_F8		(K_F7 + 1)
#define	K_F9		(K_F8 + 1)
#define	K_F10		(K_F9 + 1)
#define	K_F11		(K_F10 + 1)
#define	K_F12		(K_F11 + 1)	/* 0x10B */
/* cursor keys */
#define	K_INS		(K_F12 + 1)	/* 0x10C */
#define	K_DEL		(K_INS + 1)
#define	K_HOME		(K_DEL + 1)
#define	K_END		(K_HOME + 1)
#define	K_PGUP		(K_END + 1)
#define	K_PGDN		(K_PGUP + 1)
#define	K_LFT		(K_PGDN + 1)
#define	K_UP		(K_LFT + 1)
#define	K_DN		(K_UP + 1)
#define	K_RT		(K_DN + 1)	/* 0x115 */
/* print screen/sys rq and pause/break */
#define	K_PRNT		(K_RT + 1)	/* 0x116 */
#define	K_PAUSE		(K_PRNT + 1)	/* 0x117 */
/* these return a value but they could also act as additional bucky keys */
#define	K_LWIN		(K_PAUSE + 1)	/* 0x118 */
#define	K_RWIN		(K_LWIN + 1)
#define	K_MENU		(K_RWIN + 1)	/* 0x11A */

#if defined(__TURBOC__) || !defined(__cplusplus)
typedef enum
{	false=0, true=1 } bool;
#endif

typedef unsigned char	u8;
typedef unsigned short	u16;

typedef struct	/* circular queue */
{	bool NonEmpty;
	u8 *Data;
	u16 Size, Inptr, Outptr; } queue;

typedef struct	/* virtual console! */
{	queue Keystrokes;
	u16 KbdStatus; } console;

static console _Con;
/*****************************************************************************
	name:	inq
	action:	tries to add byte Data to queue Queue
	returns:-1 queue full
		0  success
*****************************************************************************/
int inq(queue *Queue, u8 Data)
{	u16 Temp;

	Temp=Queue->Inptr + 1;
	if(Temp >= Queue->Size)
		Temp=0;
	if(Temp == Queue->Outptr)
		return(-1);	/* full */
	Queue->Data[Queue->Inptr]=Data;
	Queue->Inptr=Temp;
	Queue->NonEmpty=true;
	return(0); }
/*****************************************************************************
	name:	deq
	action:	tries to get byte from Queue
	returns:-1  queue empty
		>=0 success (byte read)
*****************************************************************************/
int deq(queue *Queue)
{	u8 RetVal;

	if(Queue->NonEmpty == false)
		return(-1);	/* empty */
	RetVal=Queue->Data[Queue->Outptr++];
	if(Queue->Outptr >= Queue->Size)
		Queue->Outptr=0;
	if(Queue->Outptr == Queue->Inptr)
		Queue->NonEmpty=false;
	return(RetVal); }
/*****************************************************************************
	name:	kbdRead
	action:	waits for a byte from the keyboard
	returns:-1 if timeout
		nonnegative byte if success
*****************************************************************************/
static int _kbdRead(void)
{	unsigned long Timeout;
	u8 Stat, Data;

	for(Timeout=500000L; Timeout != 0; Timeout--)
	{	Stat=inportb(_KBD_STAT_REG);
/* loop until 8042 output buffer full */
		if((Stat & _KBD_STAT_OBF) != 0)
		{	Data=inportb(_KBD_DATA_REG);
/* loop if parity error or receive timeout */
			if((Stat & (_KBD_STAT_PERR | _KBD_STAT_GTO)) == 0)
				return(Data); }}
	return(-1); }
/*****************************************************************************
	name:	kbdWrite
	action:	writes Data to 8048 keyboard MCU (Adr=_KBD_DATA_REG) or
		8042 keyboard controller (Adr=_KBD_CMD_REG)
*****************************************************************************/
static void _kbdWrite(unsigned Adr, unsigned Data)
{	unsigned long Timeout;
	u8 Stat;

/* Linux code didn't have a timeout here... */
	for(Timeout=500000L; Timeout != 0; Timeout--)
	{	Stat=inportb(_KBD_STAT_REG);
/* loop until 8042 input buffer empty */
		if((Stat & _KBD_STAT_IBF) == 0)
			break; }
	if(Timeout != 0)
		outportb(Adr, Data);
/* xxx - else? */ }
/*****************************************************************************
	name:	kbdWriteRead
	action:	writes value Val to keyboard port Adr. If Len is
		non-zero, reads Len bytes from keyboard and compares
		them to Reply
	returns:0 if success
		nonzero if error (returns value of failing reply byte)
*****************************************************************************/
int _kbdWriteRead(unsigned Adr, unsigned Val, unsigned Len, u8 *Reply)
{	int RetVal;

	_kbdWrite(Adr, Val);
	for(; Len != 0; Len--)
	{	RetVal=_kbdRead();
		if(*Reply != RetVal)
		{	printf(" failed: expected 0x%02X, got 0x%02X\n",
				*Reply, RetVal);
			return(RetVal); }
		Reply++; }
	return(0); }
/*****************************************************************************
	name:	kbdInit
	action:	runs self-test on 8048 keyboard MCU and 8042 controller MCU,
		resets keyboard, programs 8048 for ScanCodeSet,
		programs 8042 for no XT-to-AT conversion,
		makes all keys make/break and fast typematic
	returns:0 if success
		nonzero if error
*****************************************************************************/
int kbdInit(unsigned ScanCodeSet)
{	unsigned Flags;
	int Result;

	printf("keyboard:");
/* xxx - probe for keyboard controller before proceding?
I don't know what will happen if the controller is bad or missing...

disable interrupts */
	Flags=critb();
/* flush pending input */
	DEBUG(printf("\n  flushing keyboard output");)
	while(_kbdRead() != -1)

⌨️ 快捷键说明

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