From 808e3dc9de1fb26eed6efcfe5665f0a66c239970 Mon Sep 17 00:00:00 2001 From: root Date: Sat, 6 Jun 2015 16:00:52 +0100 Subject: fish --- app/atkbd.c | 602 ++++++++++++++++++++++++++++++++++++++---------------------- 1 file changed, 382 insertions(+), 220 deletions(-) (limited to 'app/atkbd.c') diff --git a/app/atkbd.c b/app/atkbd.c index 0dfc9c8..63482a6 100644 --- a/app/atkbd.c +++ b/app/atkbd.c @@ -1,5 +1,6 @@ #include "project.h" + #define KBCLK (1UL << 0) #define KBCLK_PORT GPIOA #define KBCLK_IRQ NVIC_EXTI0_IRQ @@ -9,26 +10,35 @@ /*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, +#define RESYNC_GAP (7200000) /* 100ms */ + +#define ATKBD_TIMEOUT 1000 /*how long to wait for the keyboard to respond to a command in ms */ + +#define ATKBD_CLOCK_SEIZE_DELAY 200 /* how many us from pulling clock low to pulling data low, when we xmit */ +#define ATKBD_BIT_DELAY 10 /* how many us we allow from the KBD to pull clock back up */ + + +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 LED_CAPS 0x01 +#define LED_NUMLOCK 0x02 +#define LED_SCROLLOCK 0x04 + + #define ATKBD_CMD_SETLEDS 0xed #define ATKBD_CMD_GSCANSET 0xf0 #define ATKBD_CMD_SSCANSET 0xf0 @@ -38,12 +48,13 @@ typedef enum { #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_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_CMD_ECHO 0xee #define ATKBD_RET_ECHO 0xee #define ATKBD_RET_ACK 0xfa @@ -65,261 +76,412 @@ static int atkbd_nack; static int atkbd_bat; static int atkbd_echo; - - -static uint32_t cycle_diff(uint32_t a,uint32_t b) +static void +atkbd_mask_irq (void) { -return b-a; + nvic_disable_irq (KBCLK_IRQ); } - -static void atkbd_dispatch(int emul,int key,int updown) +static void +atkbd_unmask_flush_irq (void) { - -printf("KEY> %x %x %x\r\n",emul,key,updown); - - + exti_reset_request (KBCLK); + nvic_enable_irq (KBCLK_IRQ); } -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 +cycle_diff (uint32_t a, uint32_t b) { - 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; - } + return b - a; } -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); -} +static void +atkbd_dispatch (int key, int updown) +{ +/* the logic here is batshit, consult scancode.doc in the DOCS dir */ + static int fake_ctrl, pause_down; + + switch (key) + { + case AT_SC_LEFTCTRL | AT_BS_EMUL1: + fake_ctrl = updown; + break; + } + + + if (key == 0x84) + key = AT_SC_SYSRQ; + if (key == 0x77) + { + /*Grr broken MS state machine in docs */ + if ((!updown) && (pause_down)) + { + key = AT_SC_PAUSE; + pause_down = 0; + } + + if (fake_ctrl && updown) + { + key = AT_SC_PAUSE; + pause_down = 1; + } + } + + +/* Filter fakes */ + switch (key) + { + case AT_SC_LEFTCTRL | AT_BS_EMUL1: + case AT_SC_LEFTSHIFT | AT_BS_EMUL0: + case AT_SC_RIGHTSHIFT | AT_BS_EMUL0: + break; + default: + scancode_dispatch (key, updown); + } } - -int atkbd_send(uint8_t d) +static void +atkbd_data_dispatch (uint8_t byte) { -uint32_t then=ticks; -int parity=1; -uint32_t c; + 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: + /*All these need no action */ + break; + case AT_SC_EMUL0: + emul = AT_BS_EMUL0; + break; + case AT_SC_EMUL1: + emul = AT_BS_EMUL1; + break; + case ATKBD_RET_RELEASE: + release = 1; + break; + default: + atkbd_dispatch (emul | byte, !release); + emul = 0; + release = 0; + } - -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; +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; + } +} -while (!GET(KBDAT)) if (timed_out(then,ATKBD_TIMEOUT)) goto err; -while (!GET(KBCLK)) if (timed_out(then,ATKBD_TIMEOUT)) goto err; +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); + } -exti_reset_request(KBCLK); -nvic_enable_irq(KBCLK_IRQ); +} -printf("ATKBD > 0x%02x\r\n",d); -return 0; +int +atkbd_send (uint8_t d) +{ + uint32_t then = ticks; + int parity = 1; + uint32_t c; + + atkbd_mask_irq (); + + atkbd_set (0, 1); + delay_us (ATKBD_CLOCK_SEIZE_DELAY); + atkbd_set (0, 0); + delay_us (ATKBD_BIT_DELAY); + atkbd_set (1, 0); + delay_us (ATKBD_BIT_DELAY); + + + /* 8 data bits */ + 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; + } + + /* A parity bit */ + 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; + + /* two stop bits */ + while (GET (KBCLK)) + if (timed_out (then, ATKBD_TIMEOUT)) + goto err; + atkbd_set (1, 1); + 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 (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; + + atkbd_unmask_flush_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; + 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; + + atkbd_unmask_flush_irq (); + +// printf ("ATKBD >! 0x%02x\r\n", d); + return -1; } -static int atkbd_reset(void) +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; + 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) +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; + 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) +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; + 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; +} -then=ticks; -atkbd_ack=0; -atkbd_send(leds); -while (!atkbd_ack) if (timed_out(then,ATKBD_TIMEOUT)) return -1; -return 0; +int +atkbd_set_scanset (uint8_t scanset) +{ + uint32_t then = ticks; + atkbd_ack = 0; + atkbd_send (ATKBD_CMD_SSCANSET); + while (!atkbd_ack) + if (timed_out (then, ATKBD_TIMEOUT)) + return -1; + + then = ticks; + atkbd_ack = 0; + atkbd_send (scanset); + while (!atkbd_ack) + if (timed_out (then, ATKBD_TIMEOUT)) + return -1; + + return 0; } +int +atkbd_set_mb (void) +{ + uint32_t then = ticks; + atkbd_ack = 0; + atkbd_send (ATKBD_CMD_SETALL_MB); + while (!atkbd_ack) + if (timed_out (then, ATKBD_TIMEOUT)) + return -1; + + return 0; +} -void atkbd_init(void) +int +atkbd_set_mbr (void) { -atkbd_set(1,1); -delay_ms(200); + uint32_t then = ticks; + atkbd_ack = 0; + atkbd_send (ATKBD_CMD_SETALL_MBR); + while (!atkbd_ack) + if (timed_out (then, ATKBD_TIMEOUT)) + return -1; + + return 0; +} -nvic_enable_irq(NVIC_EXTI0_IRQ); +void +atkbd_init (void) +{ + atkbd_set (1, 1); + delay_ms (200); -exti_select_source(KBCLK, KBCLK_PORT); -exti_set_trigger(KBCLK, EXTI_TRIGGER_FALLING); -exti_enable_request(KBCLK); + nvic_enable_irq (NVIC_EXTI0_IRQ); -exti_reset_request(KBCLK); -nvic_enable_irq(KBCLK_IRQ); + exti_select_source (KBCLK, KBCLK_PORT); + exti_set_trigger (KBCLK, EXTI_TRIGGER_FALLING); + exti_enable_request (KBCLK); -atkbd_reset(); -atkbd_request_echo(); -atkbd_set_leds(0x07); + exti_reset_request (KBCLK); + nvic_enable_irq (KBCLK_IRQ); -} + atkbd_reset (); + atkbd_request_echo (); + atkbd_set_mbr (); + atkbd_set_scanset (2); + atkbd_set_leds (LED_CAPS); +} -- cgit v1.2.3