📄 ps2.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 + -