return; | return; | ||||
} | } | ||||
// TODO: should send only when changed from last report | |||||
if (matrix_is_modified()) { | if (matrix_is_modified()) { | ||||
host_send_keyboard_report(); | host_send_keyboard_report(); | ||||
#ifdef DEBUG_LED | #ifdef DEBUG_LED |
#endif | #endif | ||||
} | } | ||||
// TODO: send using interrupt if available | |||||
uint8_t ps2_host_send(uint8_t data) | uint8_t ps2_host_send(uint8_t data) | ||||
{ | { | ||||
bool parity; | |||||
RETRY: | |||||
parity = true; | |||||
ps2_error = 0; | |||||
uint8_t res = 0; | |||||
bool parity = true; | |||||
ps2_error = PS2_ERR_NONE; | |||||
#ifdef PS2_INT_DISABLE | |||||
PS2_INT_DISABLE(); | |||||
#endif | |||||
/* terminate a transmission if we have */ | /* terminate a transmission if we have */ | ||||
inhibit(); | inhibit(); | ||||
_delay_us(100); | _delay_us(100); | ||||
WAIT(clock_hi, 50, 8); | WAIT(clock_hi, 50, 8); | ||||
WAIT(data_hi, 50, 9); | WAIT(data_hi, 50, 9); | ||||
uint8_t res = ps2_host_recv_response(); | |||||
if (res == 0xFE && data != 0xFE) | |||||
goto RETRY; | |||||
inhibit(); | |||||
return res; | |||||
res = ps2_host_recv_response(); | |||||
ERROR: | ERROR: | ||||
#ifdef PS2_INT_ENABLE | |||||
PS2_INT_ENABLE(); | |||||
idle(); | |||||
#else | |||||
inhibit(); | inhibit(); | ||||
return 0; | |||||
#endif | |||||
return res; | |||||
} | } | ||||
/* receive data when host want else inhibit communication */ | /* receive data when host want else inhibit communication */ | ||||
/* get data received by interrupt */ | /* get data received by interrupt */ | ||||
uint8_t ps2_host_recv(void) | uint8_t ps2_host_recv(void) | ||||
{ | { | ||||
// TODO: release clock line after 100us when inhibited by error | |||||
if (ps2_error) { | |||||
ps2_host_send(0xFE); // request to resend | |||||
ps2_error = PS2_ERR_NONE; | |||||
} | |||||
return pbuf_dequeue(); | return pbuf_dequeue(); | ||||
} | } | ||||
#define DEBUGP_INIT() do { DDRC = 0xFF; } while (0) | |||||
#define DEBUGP(x) do { PORTC = x; } while (0) | |||||
ISR(PS2_INT_VECT) | ISR(PS2_INT_VECT) | ||||
{ | { | ||||
/* interrupt means start bit comes */ | |||||
pbuf_enqueue(recv_data()); | |||||
static enum { | |||||
INIT, | |||||
START, | |||||
BIT0, BIT1, BIT2, BIT3, BIT4, BIT5, BIT6, BIT7, | |||||
PARITY, | |||||
STOP, | |||||
} state = INIT; | |||||
static uint8_t data = 0; | |||||
static uint8_t parity = 1; | |||||
// TODO: abort if elapse 100us from previous interrupt | |||||
// return unless falling edge | |||||
if (clock_in()) { | |||||
goto RETURN; | |||||
} | |||||
/* release lines(idle state) */ | |||||
idle(); | |||||
_delay_us(5); | |||||
state++; | |||||
DEBUGP(state); | |||||
switch (state) { | |||||
case START: | |||||
if (data_in()) | |||||
goto ERROR; | |||||
break; | |||||
case BIT0: | |||||
case BIT1: | |||||
case BIT2: | |||||
case BIT3: | |||||
case BIT4: | |||||
case BIT5: | |||||
case BIT6: | |||||
case BIT7: | |||||
data >>= 1; | |||||
if (data_in()) { | |||||
data |= 0x80; | |||||
parity++; | |||||
} | |||||
break; | |||||
case PARITY: | |||||
if (data_in()) { | |||||
if (!(parity & 0x01)) | |||||
goto ERROR; | |||||
} else { | |||||
if (parity & 0x01) | |||||
goto ERROR; | |||||
} | |||||
break; | |||||
case STOP: | |||||
if (!data_in()) | |||||
goto ERROR; | |||||
pbuf_enqueue(data); | |||||
goto DONE; | |||||
break; | |||||
default: | |||||
goto ERROR; | |||||
} | |||||
goto RETURN; | |||||
ERROR: | |||||
DEBUGP(0xFF); | |||||
inhibit(); | |||||
ps2_error = state; | |||||
DONE: | |||||
state = INIT; | |||||
data = 0; | |||||
parity = 1; | |||||
RETURN: | |||||
return; | |||||
} | } | ||||
#endif | #endif | ||||
/* | |||||
static void ps2_reset(void) | static void ps2_reset(void) | ||||
{ | { | ||||
ps2_host_send(0xFF); | ps2_host_send(0xFF); | ||||
if (ps2_host_recv_response() == 0xFA) { | |||||
_delay_ms(1000); | |||||
ps2_host_recv_response(); | |||||
} | |||||
} | } | ||||
*/ | |||||
/* send LED state to keyboard */ | /* send LED state to keyboard */ | ||||
void ps2_host_set_led(uint8_t led) | void ps2_host_set_led(uint8_t led) | ||||
{ | { | ||||
#ifdef PS2_INT_DISABLE | |||||
PS2_INT_DISABLE(); | |||||
#endif | |||||
ps2_host_send(0xED); | ps2_host_send(0xED); | ||||
ps2_host_recv_response(); | |||||
ps2_host_send(led); | ps2_host_send(led); | ||||
ps2_host_recv_response(); | |||||
#ifdef PS2_INT_ENABLE | |||||
PS2_INT_ENABLE(); | |||||
idle(); | |||||
#endif | |||||
} | } | ||||
{ | { | ||||
uint8_t data = 0; | uint8_t data = 0; | ||||
bool parity = true; | bool parity = true; | ||||
ps2_error = 0; | |||||
ps2_error = PS2_ERR_NONE; | |||||
/* start bit [1] */ | /* start bit [1] */ | ||||
WAIT(clock_lo, 1, 1); | WAIT(clock_lo, 1, 1); | ||||
{ | { | ||||
PS2_CLOCK_DDR &= ~(1<<PS2_CLOCK_BIT); | PS2_CLOCK_DDR &= ~(1<<PS2_CLOCK_BIT); | ||||
PS2_CLOCK_PORT |= (1<<PS2_CLOCK_BIT); | PS2_CLOCK_PORT |= (1<<PS2_CLOCK_BIT); | ||||
_delay_us(1); | |||||
return PS2_CLOCK_PIN&(1<<PS2_CLOCK_BIT); | return PS2_CLOCK_PIN&(1<<PS2_CLOCK_BIT); | ||||
} | } | ||||
static inline void data_lo() | static inline void data_lo() | ||||
{ | { | ||||
PS2_DATA_DDR &= ~(1<<PS2_DATA_BIT); | PS2_DATA_DDR &= ~(1<<PS2_DATA_BIT); | ||||
PS2_DATA_PORT |= (1<<PS2_DATA_BIT); | PS2_DATA_PORT |= (1<<PS2_DATA_BIT); | ||||
_delay_us(1); | |||||
return PS2_DATA_PIN&(1<<PS2_DATA_BIT); | return PS2_DATA_PIN&(1<<PS2_DATA_BIT); | ||||
} | } | ||||
usbInit(); | usbInit(); | ||||
print_enable = true; | print_enable = true; | ||||
//debug_enable = true; | |||||
debug_enable = true; | |||||
keyboard_init(); | keyboard_init(); | ||||
/* enforce re-enumeration, do this while interrupts are disabled! */ | /* enforce re-enumeration, do this while interrupts are disabled! */ | ||||
//uint8_t fn_bits = 0; | //uint8_t fn_bits = 0; | ||||
while (1) { /* main event loop */ | while (1) { /* main event loop */ | ||||
DEBUGP(0x01); | |||||
wdt_reset(); | wdt_reset(); | ||||
usbPoll(); | usbPoll(); | ||||
host_vusb_keyboard_send(); | |||||
DEBUGP(0x02); | |||||
keyboard_proc(); | keyboard_proc(); | ||||
DEBUGP(0x03); | |||||
/* | |||||
matrix_scan(); | |||||
fn_bits = 0; | |||||
host_swap_keyboard_report(); | |||||
host_clear_keyboard_report(); | |||||
mousekey_clear_report(); | |||||
for (int row = 0; row < matrix_rows(); row++) { | |||||
for (int col = 0; col < matrix_cols(); col++) { | |||||
if (!matrix_is_on(row, col)) continue; | |||||
uint8_t code = layer_get_keycode(row, col); | |||||
if (code == KB_NO) { | |||||
// do nothing | |||||
} | |||||
else if (IS_MOD(code)) { | |||||
host_add_mod_bit(MOD_BIT(code)); | |||||
} | |||||
else if (IS_KEY(code)) { | |||||
host_add_key(code); | |||||
} | |||||
else if (IS_FN(code)) { | |||||
fn_bits |= FN_BIT(code); | |||||
} | |||||
else if (IS_MOUSEKEY(code)) { | |||||
mousekey_decode(code); | |||||
} | |||||
else { | |||||
debug("ignore keycode: "); debug_hex(code); debug("\n"); | |||||
} | |||||
} | |||||
} | |||||
DEBUGP(0x03); | |||||
layer_switching(fn_bits); | |||||
if (matrix_is_modified()) { | |||||
host_send_keyboard_report(); | |||||
} | |||||
mousekey_send(); | |||||
if (last_led != host_keyboard_led()) { | |||||
led_set(host_keyboard_led()); | |||||
last_led = host_keyboard_led(); | |||||
} | |||||
*/ | |||||
host_vusb_keyboard_send(); | |||||
} | } | ||||
} | } |
*/ | */ | ||||
PROGMEM uchar mouse_hid_report[] = { | PROGMEM uchar mouse_hid_report[] = { | ||||
/* from HID 1.11 spec example */ | /* from HID 1.11 spec example */ | ||||
0x05, 0x01, // Usage Page (Generic Desktop), | |||||
0x09, 0x02, // Usage (Mouse), | |||||
0xA1, 0x01, // Collection (Application), | |||||
0x09, 0x01, // Usage (Pointer), | |||||
0xA1, 0x00, // Collection (Physical), | |||||
0x05, 0x09, // Usage Page (Buttons), | |||||
0x19, 0x01, // Usage Minimum (01), | |||||
0x29, 0x03, // Usage Maximun (03), | |||||
0x15, 0x00, // Logical Minimum (0), | |||||
0x25, 0x01, // Logical Maximum (1), | |||||
0x95, 0x03, // Report Count (3), | |||||
0x75, 0x01, // Report Size (1), | |||||
0x81, 0x02, // Input (Data, Variable, Absolute), ;3 button bits | |||||
0x95, 0x01, // Report Count (1), | |||||
0x75, 0x05, // Report Size (5), | |||||
0x81, 0x01, // Input (Constant), ;5 bit padding | |||||
0x05, 0x01, // Usage Page (Generic Desktop), | |||||
0x09, 0x30, // Usage (X), | |||||
0x09, 0x31, // Usage (Y), | |||||
0x15, 0x81, // Logical Minimum (-127), | |||||
0x25, 0x7F, // Logical Maximum (127), | |||||
0x75, 0x08, // Report Size (8), | |||||
0x95, 0x02, // Report Count (2), | |||||
0x81, 0x06, // Input (Data, Variable, Relative), ;2 position bytes (X & Y) | |||||
0xC0, // End Collection, | |||||
0xC0, // End Collection | |||||
/* | |||||
0x05, 0x01, // USAGE_PAGE (Generic Desktop) | 0x05, 0x01, // USAGE_PAGE (Generic Desktop) | ||||
0x09, 0x02, // USAGE (Mouse) | 0x09, 0x02, // USAGE (Mouse) | ||||
0xa1, 0x01, // COLLECTION (Application) | 0xa1, 0x01, // COLLECTION (Application) | ||||
0xc0, // END_COLLECTION | 0xc0, // END_COLLECTION | ||||
0xc0, // END_COLLECTION | 0xc0, // END_COLLECTION | ||||
0xc0 // END_COLLECTION | 0xc0 // END_COLLECTION | ||||
*/ | |||||
}; | }; | ||||