From 98cba32ca9d62f6e4b7e735d177dba699b8d0698 Mon Sep 17 00:00:00 2001 From: root Date: Sat, 6 Jun 2015 12:38:36 +0100 Subject: inititalcommit --- app/atkbd.c | 325 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 325 insertions(+) create mode 100644 app/atkbd.c (limited to 'app/atkbd.c') diff --git a/app/atkbd.c b/app/atkbd.c new file mode 100644 index 0000000..0dfc9c8 --- /dev/null +++ b/app/atkbd.c @@ -0,0 +1,325 @@ +#include "project.h" + +#define KBCLK (1UL << 0) +#define KBCLK_PORT GPIOA +#define KBCLK_IRQ NVIC_EXTI0_IRQ + +#define KBDAT (1UL << 1) +#define KBDAT_PORT GPIOA + +/*Cope with lost sync */ +/*If we've had no bits for this long, it's definately the start of a new word, 72MHz units */ +#define RESYNC_GAP (7200000) /* 100ms */ + +#define ATKBD_TIMEOUT 1000 /*how long to wait for the keyboard to respond to a command in ms */ + + +typedef enum { + STATE_START=0, + STATE_BIT0, + STATE_BIT1, + STATE_BIT2, + STATE_BIT3, + STATE_BIT4, + STATE_BIT5, + STATE_BIT6, + STATE_BIT7, + STATE_PARITY, + STATE_STOP, +} atkbd_state; + + +#define ATKBD_CMD_SETLEDS 0xed +#define ATKBD_CMD_GSCANSET 0xf0 +#define ATKBD_CMD_SSCANSET 0xf0 +#define ATKBD_CMD_GETID 0xf2 +#define ATKBD_CMD_SETREP 0xf3 +#define ATKBD_CMD_ENABLE 0xf4 +#define ATKBD_CMD_RESET_DIS 0xf5 +#define ATKBD_CMD_RESET_DEF 0xf6 +#define ATKBD_CMD_SETALL_MB 0xf8 +#define ATKBD_CMD_SETALL_MBR 0xfa +#define ATKBD_CMD_RESET_BAT 0xff +#define ATKBD_CMD_RESEND 0xfe +#define ATKBD_CMD_EX_ENABLE 0xea +#define ATKBD_CMD_EX_SETLEDS 0xeb +#define ATKBD_CMD_OK_GETID 0xe8 + +#define ATKBD_RET_ECHO 0xee +#define ATKBD_RET_ACK 0xfa +#define ATKBD_RET_NAK 0xfe +#define ATKBD_RET_BAT 0xaa +#define ATKBD_RET_EMUL0 0xe0 +#define ATKBD_RET_EMUL1 0xe1 +#define ATKBD_RET_RELEASE 0xf0 +#define ATKBD_RET_HANJA 0xf1 +#define ATKBD_RET_HANGEUL 0xf2 +#define ATKBD_RET_ERR 0xff + +#define ATKBD_KEY_UNKNOWN 0 +#define ATKBD_KEY_NULL 255 + + +static int atkbd_ack; +static int atkbd_nack; +static int atkbd_bat; +static int atkbd_echo; + + + +static uint32_t cycle_diff(uint32_t a,uint32_t b) +{ +return b-a; +} + + +static void atkbd_dispatch(int emul,int key,int updown) +{ + +printf("KEY> %x %x %x\r\n",emul,key,updown); + + +} + +static void atkbd_data_dispatch(uint8_t byte) +{ +static int release; +static int emul; + +printf("ATKBD < 0x%02x\r\n",byte); + +switch (byte) { +case ATKBD_RET_ACK: + atkbd_ack++; + break; +case ATKBD_RET_NAK: + atkbd_nack++; + break; +case ATKBD_RET_BAT: + atkbd_bat++; + break; +case ATKBD_RET_ECHO: + atkbd_echo++; + break; +case ATKBD_RET_ERR: +case ATKBD_KEY_UNKNOWN: +case ATKBD_RET_HANJA: /*Don't handle japanese or korean for the moment*/ +case ATKBD_RET_HANGEUL: /*Don't handle japanese or korean for the moment*/ + /*All these need no action */ + break; +case ATKBD_RET_EMUL0: + emul=1; + break; +case ATKBD_RET_EMUL1: + emul=2; + break; +case ATKBD_RET_RELEASE: + release=1; + break; +default: + atkbd_dispatch(emul,byte,release); + emul=0; + release=0; +} + +} + + +void exti0_isr(void) +{ + static uint32_t last_interrupt=0; + static atkbd_state state=STATE_START; + static uint8_t atkbd_byte; + static int parity; + + uint32_t now,diff; + int d; + + d=!!GET(KBDAT); + + exti_reset_request(KBCLK); + + now=dwt_read_cycle_counter(); + diff=cycle_diff(last_interrupt,now); + last_interrupt=now; + + + if (diff>RESYNC_GAP) state=STATE_START; + + + switch (state) { + case STATE_START: + atkbd_byte=0; + parity=0; + if (!d) state++; + break; + case STATE_BIT0: + case STATE_BIT1: + case STATE_BIT2: + case STATE_BIT3: + case STATE_BIT4: + case STATE_BIT5: + case STATE_BIT6: + case STATE_BIT7: + atkbd_byte|=d<<(state-STATE_BIT0); + /* fall through*/ + case STATE_PARITY: + parity ^= d; + state++; + break; + case STATE_STOP: + if (d && parity) atkbd_data_dispatch(atkbd_byte); + state=STATE_START; + break; + } +} + + + +void atkbd_set(int clk,int dat) +{ +if (clk) { + MAP_INPUT_PU(KBCLK); +} else { + CLEAR(KBCLK); + MAP_OUTPUT_PP(KBCLK); +} + + +if (dat) { + MAP_INPUT_PU(KBDAT); +} else { + CLEAR(KBDAT); + MAP_OUTPUT_PP(KBDAT); +} + +} + + +int atkbd_send(uint8_t d) +{ +uint32_t then=ticks; +int parity=1; +uint32_t c; + + +nvic_disable_irq(KBCLK_IRQ); + +#define PS2_CLOCK_SEIZE_DELAY 200 +#define PS2_BIT_DELAY 10 + +atkbd_set(0,1); +delay_us(PS2_CLOCK_SEIZE_DELAY); +atkbd_set(0,0); +delay_us(PS2_BIT_DELAY); +atkbd_set(1,0); +delay_us(PS2_BIT_DELAY); + +for (c=1;c<0x100;c<<=1) { +while (GET(KBCLK)) if (timed_out(then,ATKBD_TIMEOUT)) goto err; +atkbd_set(1,c&d); +parity^=!!(c&d); +while (!GET(KBCLK)) if (timed_out(then,ATKBD_TIMEOUT)) goto err; +} +while (GET(KBCLK)) if (timed_out(then,ATKBD_TIMEOUT)) goto err; +atkbd_set(1,parity); +while (!GET(KBCLK)) if (timed_out(then,ATKBD_TIMEOUT)) goto err; + +while (GET(KBCLK)) if (timed_out(then,ATKBD_TIMEOUT)) goto err; +while (!GET(KBCLK)) if (timed_out(then,ATKBD_TIMEOUT)) goto err; + +atkbd_set(1,1); +while (GET(KBDAT)) if (timed_out(then,ATKBD_TIMEOUT)) goto err; +while (GET(KBCLK)) if (timed_out(then,ATKBD_TIMEOUT)) goto err; + + + +while (!GET(KBDAT)) if (timed_out(then,ATKBD_TIMEOUT)) goto err; +while (!GET(KBCLK)) if (timed_out(then,ATKBD_TIMEOUT)) goto err; + +exti_reset_request(KBCLK); +nvic_enable_irq(KBCLK_IRQ); + +printf("ATKBD > 0x%02x\r\n",d); + +return 0; + +err: +atkbd_set(1,1); +while (!GET(KBDAT)) if (timed_out(then,ATKBD_TIMEOUT)) goto err; +while (!GET(KBCLK)) if (timed_out(then,ATKBD_TIMEOUT)) goto err; + +exti_reset_request(KBCLK); +nvic_enable_irq(KBCLK_IRQ); + +printf("ATKBD >! 0x%02x\r\n",d); +return -1; +} + +static int atkbd_reset(void) +{ +uint32_t then=ticks; +atkbd_bat=0; +atkbd_send(ATKBD_CMD_RESET_BAT); +while (!atkbd_bat) if (timed_out(then,ATKBD_TIMEOUT)) return -1; + +then=ticks; +atkbd_ack=0; +atkbd_send(ATKBD_CMD_SETALL_MBR); +while (!atkbd_ack) if (timed_out(then,ATKBD_TIMEOUT)) return -1; + + +return 0; +} + +int atkbd_request_echo(void) +{ +uint32_t then=ticks; +atkbd_ack=0; +atkbd_send(ATKBD_CMD_ECHO); +while (!atkbd_echo) if (timed_out(then,ATKBD_TIMEOUT)) return -1; + +return 0; +} + + +int atkbd_set_leds(uint8_t leds) +{ +uint32_t then=ticks; +atkbd_ack=0; +atkbd_send(ATKBD_CMD_SETLEDS); +while (!atkbd_ack) if (timed_out(then,ATKBD_TIMEOUT)) return -1; + +then=ticks; +atkbd_ack=0; +atkbd_send(leds); +while (!atkbd_ack) if (timed_out(then,ATKBD_TIMEOUT)) return -1; + +return 0; +} + + +void atkbd_init(void) +{ +atkbd_set(1,1); +delay_ms(200); + +nvic_enable_irq(NVIC_EXTI0_IRQ); + + +exti_select_source(KBCLK, KBCLK_PORT); +exti_set_trigger(KBCLK, EXTI_TRIGGER_FALLING); +exti_enable_request(KBCLK); + +exti_reset_request(KBCLK); +nvic_enable_irq(KBCLK_IRQ); + + +atkbd_reset(); +atkbd_request_echo(); +atkbd_set_leds(0x07); + + +} + + -- cgit v1.2.3