#include "kbd.h" #include #include #include #include #include static volatile int8_t kbd_state = 0; static volatile uint8_t kbd_input = 0; static volatile uint8_t kbd_output = 0; static volatile uint8_t kbd_flags = 0; static volatile uint8_t ts = 10; static inline bool kbd_data() { return (PINC & (1 << 0)); } static inline bool kbd_clock() { return (PINC & (1 << 1)); } static inline void kbd_clock_down() { DDRC |= 0x02; PORTC &= ~0x02; } static inline void kbd_clock_in() { DDRC &= ~0x02; PORTC |= 0x02; } static inline void kbd_data_set(bool state) { if (state) PORTC |= 0x01; else PORTC &= ~0x01; } static inline void kbd_data_out() { DDRC |= 0x01; } static inline void kbd_data_in() { DDRC &= ~0x01; PORTC |= 0x01; } static inline void kbd_wait() { while (kbd_state) {} } ISR(PCINT1_vect) { if (kbd_clock()) return; if (kbd_state < 0) { if (kbd_state >= -8) { kbd_data_set(kbd_output & _BV(-1-kbd_state)); } else if (kbd_state == -9) { kbd_data_set(!(__builtin_popcount(kbd_output) & 1)); } else if (kbd_state == -10) { kbd_data_in(); } else { kbd_state = 0; return; } kbd_state--; return; } bool data = kbd_data(); if (kbd_state == 0) { if (!data) { /* start bit */ kbd_input = 0; kbd_state++; } return; } if (kbd_state <= 8) { if (data) kbd_input |= _BV(kbd_state-1); kbd_state++; return; } if (kbd_state == 9) { if ((__builtin_popcount(kbd_input) & 1) == data) kbd_flags |= KBD_FLAG_ERROR; kbd_state++; return; } kbd_state = 0; if (kbd_flags & KBD_FLAG_ERROR) { /* Retry */ return; } if (kbd_input == 0xe0) { kbd_flags |= KBD_FLAG_EXT; return; } if (kbd_input == 0xf0) { kbd_flags |= KBD_FLAG_BREAK; return; } uint16_t code = kbd_input; if (kbd_flags & KBD_FLAG_EXT) code |= 0xe000; kbd_handle(code, !(kbd_flags & KBD_FLAG_BREAK)); kbd_flags = 0; } void kbd_send(uint8_t command) { kbd_wait(); kbd_clock_down(); _delay_us(100); kbd_data_out(); kbd_data_set(false); _delay_us(10); kbd_clock_in(); kbd_output = command; kbd_state = -1; kbd_wait(); /* wait for ack */ while (!kbd_state) {} kbd_wait(); } void kbd_init(void) { DDRC &= ~0x03; PORTC |= 0x03; PCMSK1 = (1 << PCINT9); PCICR = (1 << PCIE1); }