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

📄 ps2.c

📁 Embest EudKit-II教学系统配Samsung S3C44B0处理器的部分测试程序。
💻 C
字号:
/*********************************************************************************************
* File:	ps2.c
* Author:	embest
* Desc:	ps2 keyboard/mouse controller simulator
* History:
*********************************************************************************************/
#include "44b.h"
#include "ps2.h"


typedef void (*ISR_CALLBACK)(void);


#define DISABLE_INT()	ARMDisableInt()
#define ENABLE_INT()	ARMEnableInt()


/*
* registers
*/
static unsigned char reg_ibuffer;
static unsigned char reg_obuffer;
static unsigned char reg_status;
static unsigned char reg_control;


/*
* inner shift registers
*/
static unsigned char reg_ishift;
static unsigned char reg_oshift;


/*
* interrupt service callback rontine
*/
static ISR_CALLBACK keyboard_isr;
static ISR_CALLBACK mouse_isr;


/*
* functions prototype
*/
static void prepare_receive(void);


/*
* name:		ARMDisableInt
* func:		disable interrupt
* para:		none
* ret:		none
* comment:		
*/
static inline void ARMDisableInt(void)
{
	__asm__ __volatile__
	("
	mrs		r0, cpsr
	orr		r0, r0, #0x80
	msr		cpsr_all, r0
	");
}


/*
* name:		ARMEnableInt
* func:		enable interrupt
* para:		none
* ret:		none
* comment:		
*/
static inline void ARMEnableInt(void)
{
	__asm__ __volatile__("
	mrs		r0, cpsr
	bic		r0, r0, #0x80
	msr		cpsr_all, r0
	");
}


/*
* name:		ARMIsDisableInt
* func:		test interrupt state
* para:		none
* ret:		disable interrupt return 1, otherwise 0
* comment:		
*/
static inline int ARMIsDisableInt(void)
{
	__asm__ __volatile("
	mrs		r0, cpsr
	and		r0, r0, #0x80
	mov		r0, r0, lsr#7
	");
}


/*
* name:		init_pin
* func:		initialize I/O pin
* para:		none
* ret:		none
* comment:		
*/
static inline void init_pin(void)
{
	/* pull up resistor attached to the GPE0 is enabled. */
	rPUPE &= 0xfffffffe;
	/* pull up resistor attached to the GPG4 is enabled. */
	rPUPG &= 0xffffffef;
}


/*
* name:		set_clock_output
* func:		set clock pin I/O status
* para:		output		---input, 1/output, 0/input, -1/interrupt
* ret:		none
* comment:		
*/
static inline void set_clock_output(int output)
{
	unsigned int temp;

	temp = rPCONG & 0xfffffcff;
	switch(output)
	{
	case 0:
		/* GPG4 is input */
		break;
	case -1:
		/* GPG4 is extern interrupt */
		temp |= 0x00000300;
		break;
	case 1:
	default:
		/* GPG4 is output */
		temp |= 0x00000100;
		break;
	}

	rPCONG = temp;
}


/*
* name:		clock_interrupt
* func:		active clock pin interrupt
* para:		falling		---input, 1/falling edge triggered, 0/rising edge triggered
* ret:		none
* comment:		
*/
static inline void clock_interrupt(int falling)
{
	int temp;

	temp = rEXTINT & 0xfff8ffff;
	if(falling)
	{
		/* falling edge triggered */
		temp |= 0x00020000;
	}
	else
	{ 
		/* Rising edge triggered */
		temp |= 0x00040000;
	}
	rEXTINT = temp;

	/* change GPG4 for interrupt */
	rPCONG |= 0x00000300;
}


/*
* name:		set_data_output
* func:		set data pin I/O status
* para:		output		---input, 1/data output, 0/data input
* ret:		none
* comment:		
*/
static inline void set_data_output(int output)
{
	unsigned int temp;

	if(output)
	{
		/* GPE0 is output */
		temp = rPCONE & 0xfffffffc;
		temp |= 0x00000001;
		rPCONE = temp;
		/* set GPE0 to 0 */
		rPDATE &= 0xfffffffe;

	}
	else
	{
		/* GPE0 is input */
		rPCONE &= 0xfffffffc;
	}
}


/*
* name:		close_input
* func:		close ps2 interface data input
* para:		none
* ret:		none
* comment:		
*/
static inline void close_input(void)
{
	int temp;

	/* Rising edge triggered */
	temp = rEXTINT & 0xfff8ffff;
	temp |= 0x00040000;
	rEXTINT = temp;

	/* GPG4 is outpt */
	temp = rPCONG & 0xfffffcff;
	temp |= 0x00000100;
	rPCONG = temp;

	/* set GPG4 to 0, pull down device clock pin */
	rPDATG &= 0xffffffef;

	/* GPE0 is input */
	rPCONE &= 0xfffffffc;
}


/*
* name:		get_bit
* func:		get a bit data from data pin(input)
* para:		none
* ret:		0 or 1/a bit data , -1/failed
* comment:		
*/
static inline int get_bit(void)
{
	int bit, time = 0;

	while((rPDATG & 0x10))
	{
		if(time >= 5000) return -1;
		time++;
	}
	bit = rPDATE & 0x01;

	/* wait for clock to high */
	while(!(rPDATG & 0x10));

	return bit;
}


/*
* name:		set_bit
* func:		set a bit data to data pin(output)
* para:		none
* ret:		1/set a bit data successful, 0/failed
* comment:		
*/
static inline int set_bit(unsigned char bit)
{
	int temp, time = 0;

	temp = rPDATE & 0xfffffffe;
	temp |= bit & 0x01;

	/* wait for clock to low */
	while(!(rPDATG & 0x10));
	rPDATE = temp;

	/* wait for clock to high */
	while((rPDATG & 0x10))
	{
		if(time >= 5000) return 0;
		time++;
	}

	return 1;
}


/*
* name:		check_parity
* func:		check a byte parity
* para:		data		---input, a byte
* ret:		1/even number 1, 0/odd number 1
* comment:		
*/
static unsigned char check_parity(unsigned char data)
{
	unsigned char i, result = 1;

	for(i=0; i<8; i++)
	{
		if(data & (1<<i))
			result = !result;
	}

	return result;
}


/*
* name:		data_in_isr
* func:		receive data interrupt service routine
* para:		none
* ret:		none
* comment:		
*/
static void data_in_isr(void)
{
	int i, start, parity, stop;

	/* clear interrupt pend */
	rEXTINTPND = 0x01;
	rI_ISPC = BIT_EINT4567;

	/* set clock pin input */
	set_clock_output(0);

	/*  start bit */
	start = get_bit();
	if(start == -1)
	{
		reg_status |= BS_TO;
		if(reg_status & BS_IBF) close_input();
		else prepare_receive();
		return;
	}

	/* reset input shift register */
	reg_ishift = 0;

	/* data bits */
	for(i = 0; i < 8; i++)
	{	
		reg_ishift >>= 1;
		switch(get_bit())
		{
		case 1:	reg_ishift |= 0x80;
		case 0: break;
		default:
			reg_status |= BS_TO;
			if(reg_status & BS_IBF) close_input();
			else prepare_receive();
			return;
		}
	}

	/* parity bit */
	parity = get_bit();
	if(parity == -1)
	{
		reg_status |= BS_TO;
		if(reg_status & BS_IBF) close_input();
		else prepare_receive();
		return;
	}
	if(parity != check_parity(reg_ishift))
		reg_status |= BS_PERR;

	/* stop bit */
	stop = get_bit();
	if(stop == -1)
	{
		reg_status |= BS_TO;
		if(reg_status & BS_IBF) close_input();
		else prepare_receive();
		return;
	}

	/* save data */
	reg_ibuffer = reg_ishift;
	reg_status |= BS_IBF;
	
	/* interrupt callback */
	if((reg_control & BC_INT) && keyboard_isr != 0)
		keyboard_isr();
	if((reg_control & BC_INT2) && mouse_isr != 0)
		mouse_isr();

	if(reg_status & BS_IBF) close_input();
	else prepare_receive();
}


/*
* name:		data_out_isr
* func:		transmited data interrupt service routine
* para:		none
* ret:		none
* comment:		
*/
static void data_out_isr(void)
{
	int i, parity, ack;

	/* clear interrupt pend */
	rEXTINTPND = 0x01;
	rI_ISPC = BIT_EINT4567;

	/* set clock pin input */
	set_clock_output(0);

	/* get data output shift register */
	reg_oshift = reg_obuffer;

	/* clear output buffer flag */
	reg_status &= ~BS_OBF;

	/*  start bit */
	if(!set_bit(0))
	{
		reg_status |= BS_TO;
		if(reg_status & BS_IBF) close_input();
		else prepare_receive();
		return;
	}

	/* parity bit */
	parity = check_parity(reg_oshift);

	/* data bits */
	for(i = 0; i < 8; i++)
	{	
		if(!set_bit(reg_oshift))
		{
			reg_status |= BS_TO;
			if(reg_status & BS_IBF) close_input();
			else prepare_receive();
			return;
		}
	}

	/* parity bit */
	if(!set_bit(parity))
	{
		reg_status |= BS_TO;
		if(reg_status & BS_IBF) close_input();
		else prepare_receive();
		return;
	}

	/* stop bit */
	if(!set_bit(1))
	{
		reg_status |= BS_TO;
		if(reg_status & BS_IBF) close_input();
		else prepare_receive();
		return;
	}

	/* set data input */
	set_data_output(0);

	/* read ack bit */
	ack = get_bit();
	if(ack == -1)
		reg_status |= BS_TO;

	if(reg_status & BS_IBF) close_input();
	else prepare_receive();
}


/*
* name:		prepare_receive
* func:		set clock pin falling edge triggered interrupt,
*			and setup isr, prepare receive data
* para:		none
* ret:		none
* comment:		
*/
static void prepare_receive(void)
{
	/* falling edge triggered interrupt */
	clock_interrupt(1);

	/* set interrupt service routine */
	pISR_EINT4567 = (unsigned int)data_in_isr;
}


/*
* name:		prepare_transmit
* func:		set clock pin rising edge triggered interrupt,
*			and setup isr, prepare transmit data
* para:		none
* ret:		none
* comment:		
*/
static void prepare_transmit(void)
{
	volatile int i;

	/* delay 100us */
	for(i=0; i<500; i++);

	/* data out */
	set_data_output(1);

	/* rising edge triggered interrupt */
	clock_interrupt(0);

	/* set interrupt service routine */
	pISR_EINT4567 = (unsigned int)data_out_isr;
}


/*
* name:		reg_read
* func:		read register data.
* para:		addr		---input, register address
* ret:		a byte data
* comment:		
*/
unsigned char reg_read(unsigned int addr)
{
	unsigned char data;

	DISABLE_INT();
	switch(addr)
	{
	case REG_DATA://0x60
		data = reg_ibuffer;
		reg_status &= ~(BS_IBF);
		prepare_receive();
		break;
	case REG_STATUS://0x64
		data = reg_status;
		reg_status &= ~(BS_PERR|BS_TO);
		break;
	case REG_W_CONTROL://0x20
		data = reg_control;
		break;
	default:
		data = data;
		break;
	}
	ENABLE_INT();

	return data;
}


/*
* name:		reg_write
* func:		write a byte to register
* para:		addr		---input, register address
			data		---input, data
* ret:		none
* comment:		
*/
void reg_write(unsigned int addr, unsigned char data)
{
	DISABLE_INT();
	switch(addr)
	{
	case REG_DATA://0x60
		reg_obuffer = data;
		reg_status |= BS_OBF;
		reg_status &= ~(BS_A2);
		prepare_transmit();
		break;
	case 0x64:
		data &= ~(BC_RES1|BC_RES2);
		reg_status |= BS_A2;
		reg_control = data;
		break;
	}
	ENABLE_INT();
}


/*
* name:		set_keyboard_isr_callback
* func:		set keyboard isr callback routine
* para:		isr			---input, callback routine
* ret:		none
* comment:		
*/
void set_keyboard_isr_callback(void (*isr)(void))
{
	DISABLE_INT();
	keyboard_isr = isr;
	ENABLE_INT();
}


/*
* name:		set_mouse_isr_callback
* func:		set mouse isr callback routine
* para:		isr			---input, callback routine
* ret:		none
* comment:		
*/
void set_mouse_isr_callback(void (*isr)(void))
{
	DISABLE_INT();
	mouse_isr = isr;
	ENABLE_INT();
}


/*
* name:		init_ps2
* func:		initialize ps2 interface
* para:		none
* ret:		none
* comment:		
*/
void init_ps2(void)
{
	DISABLE_INT();
	keyboard_isr = 0;
	mouse_isr = 0;
	reg_ibuffer = 0;
	reg_obuffer = 0;
	reg_status = (BS_SYS | BS_INH);
	reg_control = 0;
	init_pin();
	close_input();

	rEXTINTPND = 0xf;								// Clear EXTINTPND reg
    rI_ISPC |= BIT_EINT4567;						// Clear all interrupt pend
	rINTMSK &= ~(BIT_GLOBAL | BIT_EINT4567);		// enable extend interrupt
	ENABLE_INT();
}


/*
* name:		close_ps2
* func:		close ps2 interface, stop transfers data
* para:		none
* ret:		none
* comment:		
*/
void close_ps2(void)
{
	DISABLE_INT();
	close_input();
}

⌨️ 快捷键说明

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