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

📄 ps2_kb.c

📁 瑞萨M16C编写的模拟PS2主机与标准键盘通讯程序.完整的工程文件,测试可用.
💻 C
字号:
// Implementation of a PS/2 keyboard driver

#include "sfr62p.h"#include "kb.h"#include "machine.h"#include "skp_bsp.h"#include "misc.h"#include <ctype.h>// Scan code lookup table is in "scancodes.h"#include "scancodes.h"// Local definitions#define PS2_BUFFER_SIZE 8         // buffer for deoded keyboard keys
// Various flags used for control#define 	PS2_CTRL_FLAG 		0x01        // mask for "ctrl down"#define 	PS2_SHIFT_FLAG 		0x02       	// mask for "shift down"#define 	PS2_CAPS_FLAG 		0x04        // mask for "caps lock down"#define 	PS2_BREAK_FLAG 		0x08       	// mask for "break code was received"#define 	PS2_ARROW_FLAG 		0x10       	// mark for "first code for an arrow key was received"#define 	PS2_RAW_FLAG 		0x20		// "raw" mode: the keys are not decoded, rather saved in the buffer as they are (for internal purposes)#define 	PS2_READY_FLAG 		0x40		// 'data ready' indication in RAW mode
// Keyboard specific values#define 	PS2_BREAK_CODE 		0xF0       	// break code#define 	PS2_IGN7_CODE 		0xE1        // when this code is received, the next 7 codes will be ignored#define 	PS2_CTRL_CODE 		0x14        // code for left ctrl key (only the left one is used)#define		PS2_SHIFT_CODE		0x12       	// code for left shift key (only the left one is used)#define 	PS2_CAPS_CODE 		0x58        // code for "caps lock"
#define 	PS2_ARROW_CODE 		0xE0       	// first scan code for arrow keys#define 	PS2_LEFT_CODE 		0x6B        // code for left key#define 	PS2_RIGHT_CODE 		0x74       	// code for right key#define 	PS2_UP_CODE 		0x75        // code for up key#define 	PS2_DOWN_CODE 		0x72        // code for down key
// PS2 keyboard commands#define 	PS2_CMD_RESET 		0xFF        // software reset#define 	PS2_CMD_LIGHTS 		0xED		// set kb lights#define 	PS2_CMD_SET_RATE 	0xF3		// set typematic rate/delay#define 	PS2_CAPS_VALUE 		0x04		// value for "caps lock" in previous command// Declare sections for program/const data//#pragma SECTION program remove_1_program//#pragma SECTION rom remove_1_rom// Lookup table for CTRL+char commandstatic const u8 ps2_ctrl_lookup[ ] = {  'c', KB_INTERRUPT,  'u', KB_PGUP,  'v', KB_PGDOWN,  'a', KB_HOME,  'e', KB_END,  'y', KB_CLRLINE,  'q', KB_CMDMODE,  'f', KB_FIND,  's', KB_SAVE,  'g', KB_GOTO};static u8 ps2_buf[ PS2_BUFFER_SIZE ]; // data bufferstatic u8 ps2_write_index, ps2_read_index, ps2_read_size; // buffer control variablesstatic u8 ps2_bits, ps2_data, ps2_flags, ps2_ignore, ps2_raw_data; // other control variables// *****************************************************************************// Internal functions// Waits for kbd clock to get high and then lowstatic void ps2_wait_highlow( void ){	while( PS2_CLOCK_LINE == 0 ); // loop until clock high	while( PS2_CLOCK_LINE == 1 ); // loop until clock low  }// Send a command to the PS2 keyboard// Input: ncmd - number of command bytes// Input: nres - number of expected responses to 'command'// Innput: pres - pointer to input and output data// Return: 1 - OK, 0 - errorstatic u8 ps2_send_command( u8 ncmd, u8 nres, u8 *pd ){  	  	u8 i, par, cmd, k;  	int0ic = 0x00; // temporary disable the keyboard interrupt
	  	// Now send the command(s)  	for( k = 0; k < ncmd; k ++ )	{  		PS2_CLOCK_DIR = 1; // set clock low  		delay( 64 );  		PS2_DATA_DIR = 1; // set data low  		PS2_CLOCK_DIR = 0; // release clock  		ps2_wait_highlow();		cmd = pd[ k ];	  	for( i = par = 0; i < 8; i ++, cmd >>= 1 )   		{    		PS2_DATA_DIR = ~( cmd & 1 ); // write data    		if( cmd & 1 )      			par ++;    		ps2_wait_highlow();  		}
		  		// Send parity now  		PS2_DATA_DIR = par & 1 ;  		par = 0xFF; // will be used later as an error indicator  		ps2_wait_highlow();
		  		// Release data line (stop bit)  		PS2_DATA_DIR = 0;  		ps2_wait_highlow();
		  		// Read and interpret ACK bit  		if( PS2_DATA_LINE == 1 ) // error, mark it in 'par'    		par = 0;  		while( PS2_CLOCK_LINE == 0 );  		PS2_CLOCK_DIR = 1; // clock is low to inhibit transmision for now  		if( par == 0 ) // ACK error  		{			ir_int0ic = 0; // clear pending interrupts  			int0ic = 0x04; // restore the keyboard interrupt  			PS2_CLOCK_DIR = 0; // release the clock and allow transmission again      		return 0;  			}  	}
 	ir_int0ic = 0; // clear pending interrupts  	int0ic = 0x04; // restore the keyboard interrupt
	  	if( nres > 0 )  		ps2_flags |= PS2_RAW_FLAG; // set the isr in 'raw' mode (no data decode)
		  	PS2_CLOCK_DIR = 0; // release clock, allow transmission from KB again
	  	for( i = 0; i < nres; i ++ ) // read all responses  	{  		while( ( ps2_flags & PS2_READY_FLAG ) == 0 ); // wait for response  		ps2_flags &= ~PS2_READY_FLAG;  		pd[ i ] = ps2_raw_data;  	}
	  	if( nres > 0 )  		ps2_flags &= ~PS2_RAW_FLAG; // no more "raw" mode
  	return 1;}// Add the specified data to the keyboard buffer// Input: data - data to addstatic void ps2_add_to_buffer( u8 data ){	ps2_buf[ ps2_write_index ] = data; // save received data to buffer	ps2_write_index = ( ps2_write_index + 1 ) % PS2_BUFFER_SIZE; // next position in buffer	ps2_read_size = ( ps2_read_size < PS2_BUFFER_SIZE ) ? ps2_read_size + 1 : PS2_BUFFER_SIZE;    }// INT0 interrupt routine (for keyboard clock)#pragma INTERRUPT int0_isrvoid int0_isr( void ){  	s8 left, right, idx=0;	u8 c, ca[ 2 ];  		ca[ 0 ] = 0; // no command must be sent to the kb  	// Sample bit. Start/stop/parity are ignored  	if( ( ps2_bits >= 1 ) && ( ps2_bits <= 8 ) ) // actual data bits  	{    	ps2_data >>= 1;      	ps2_data |= PS2_DATA_LINE << 7;  	}  	ps2_bits ++;    	if( ps2_bits < 11 ) // still waiting for data     	return;  	if( ps2_flags & PS2_RAW_FLAG ) // raw data mode, write to buffer and return  	{    	ps2_flags |= PS2_READY_FLAG; // special indication in 'raw' mode: data is ready    	ps2_raw_data = ps2_data;    	goto isrexit;	}	if( ps2_ignore == 0 ) // this byte should not be ignored  	{    	// Check for special cases (shift/ctrl/alt/caps/arrows/break)    	switch( ps2_data )    	{    		case PS2_IGN7_CODE:        		ps2_ignore = 7;        		goto isrexit;      		case PS2_BREAK_CODE:        		ps2_ignore = 1;        		ps2_flags |= PS2_BREAK_FLAG;        		goto isrexit;      		case PS2_ARROW_CODE:        		ps2_ignore = 1;        		ps2_flags |= PS2_ARROW_FLAG;        		goto isrexit;      		case PS2_CTRL_CODE:        		ps2_flags |= PS2_CTRL_FLAG;        		goto isrexit;      		case PS2_SHIFT_CODE:        		ps2_flags |= PS2_SHIFT_FLAG;        		goto isrexit;      		case PS2_CAPS_CODE:        		ps2_flags ^= PS2_CAPS_FLAG; // invert CAPS flag        		// Send "lights on" command        		ca[ 0 ] = PS2_CMD_LIGHTS;        		ca[ 1 ] = ( ps2_flags & PS2_CAPS_FLAG ) ? PS2_CAPS_VALUE : 0;        		goto isrexit;
			default:
				break;    	}    	// Now check for the other allowed keys (lookup)    	// As the scancode table is ordered, use binary search to speed things up    	left = 0;    	right = PS2_TABLE_SIZE - 1;
		
		//二分查找法    	while( left <= right )    	{      		idx = ( left + right ) >> 1;      		c = ps2_key_table[ idx ];      		if( c == ps2_data ) // found        		break;      		if( ps2_data < c )        		right = idx - 1;      		else        		left = idx + 1;    	}
		    	if( left > right ) // key not found, ignore    		goto isrexit;
			    	ps2_data = ps2_key_map[ idx ][ PS2_SIMPLE_INDEX ];    	// Key found, now look to see if CTRL is active and a valid combination was pressed    	if( ps2_flags & PS2_CTRL_FLAG )    	{      		for( left = 0; left < sizeof( ps2_ctrl_lookup ); left += 2 )        	if( ps2_ctrl_lookup[ left ] == ps2_data )        	{         	 	ps2_data = ps2_ctrl_lookup[ left + 1 ];          		break;        	}      		if( ps2_data == KB_INTERRUPT ) // special case, call LUA for interrupt handling        		//lua_setstophook();
				asm("nop");    	}    	else // no CTRL, check for SHIFT and CAPS    	{      		if( ps2_flags & PS2_SHIFT_FLAG ) // shift found, change character        	ps2_data = ps2_key_map[ idx ][ PS2_SHIFTED_INDEX ];      		// If 'caps lock' is on, modify the character if it is a letter      		if( ( ps2_flags & PS2_CAPS_FLAG ) && ( isupper( ps2_data ) || islower( ps2_data ) ) )        	ps2_data = toupper( ps2_data );    	}          	// Add the decoded character to buffer ... finally :)    	ps2_add_to_buffer( ps2_data );  	}
	  	else // the received code is not actual data, check for special cases  	{    	if( ps2_flags & PS2_BREAK_FLAG ) // break code    	{      		// Check for break of ctrl/shift/caps      		switch( ps2_data )      		{        		case PS2_CTRL_CODE:          			ps2_flags &= ~PS2_CTRL_FLAG;          			break;        		case PS2_SHIFT_CODE:          			ps2_flags &= ~PS2_SHIFT_FLAG;          			break;      		}      		ps2_flags &= ~PS2_BREAK_FLAG;               	}
			    if( ps2_flags & PS2_ARROW_FLAG ) // arrow code	    {	      	c = 0;	      	switch( ps2_data )	      	{	        	case PS2_LEFT_CODE:	          		c = KB_LEFT;	          		break;		        case PS2_RIGHT_CODE:			    	c = KB_RIGHT;			        break;		        case PS2_UP_CODE:			        c = KB_UP;			        break;		        case PS2_DOWN_CODE:		          	c = KB_DOWN;		          	break;		        case PS2_BREAK_CODE: // special break code, re-initialize the 'ignore' counter		          	ps2_ignore = 2;		          	break;	      	}	      	if( c != 0 )	        	ps2_add_to_buffer( c );	      	ps2_flags &= ~PS2_ARROW_FLAG;         	    }    	ps2_ignore --; 	}
	 isrexit:
  	ps2_bits = ps2_data = 0;
	  	if( ca[ 0 ] != 0 ) // must send a command    	ps2_send_command( 2, 0, ca );}// Initialize the PS2 keyboardvoid ps2_init( void ){
	u8 res[ 2 ];  	PS2_CLOCK_DIR = PS2_CLOCK_DIR = 0; // set to input, will be pulled high by external resistors	PS2_DATA_LINE = PS2_CLOCK_LINE = 0; // this will be output when direction is set to 1
		// Initialize internal variables	ps2_write_index = ps2_read_index = ps2_read_size = 0;	ps2_bits = ps2_data = ps2_flags = ps2_ignore = 0;
	
	// Enable interrupt on clock line, level 3, falling edge polarity	ir_int0ic = 0; // clear pending interrupts  	int0ic = 0x03;
		// Reset the keyboard	res[ 0 ] = PS2_CMD_RESET;	ps2_send_command( 1, 2, res );
		// Set typematic rate_delay;	res[ 0 ] = PS2_CMD_SET_RATE;	res[ 1 ] = 0;	ps2_send_command( 2, 1, res );}// Returns 1 if a key is available, 0 otherwisestatic s8 keypressed( void ){ 	return ps2_read_size > 0;}// Get a character (without timeout)static u8 getchar( void ){
	s8 c;  	c = ps2_buf[ ps2_read_index ];	DISABLE_IRQ	ps2_read_size --;	ENABLE_IRQ	ps2_read_index = ( ps2_read_index + 1 ) % PS2_BUFFER_SIZE;	return c;}// Wait for a character and return itstatic u8 waitchar( void ){	while( keypressed() == 0 );	return getchar();}// End of internal functions// *****************************************************************************// Initialize the driver// Input: a pointer to a keyboard driver context structure that must be filledvoid ps2_kb_init( KBDRV_CTX *pctx ) {	ps2_init();	pctx->waitchar = waitchar;	pctx->keypressed = keypressed;	pctx->getchar = getchar;}

⌨️ 快捷键说明

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