From cd568297a41e5a6f2e130de82c07b6b789d34f4b Mon Sep 17 00:00:00 2001 From: root Date: Sat, 13 Jun 2015 13:08:23 +0100 Subject: add usb wakeup support, all keys up on bad data, and resend for parity errors --- app/atkbd.c | 127 +++++++++++++++++++++++++++++++++++++------------------ app/consumer.c | 15 +++++-- app/keyboard.c | 21 +++++++-- app/keymap.c | 6 +++ app/project.h | 4 ++ app/prototypes.h | 7 +++ app/ticker.c | 11 +++++ app/usb.c | 42 ++++++++++++++++++ 8 files changed, 185 insertions(+), 48 deletions(-) diff --git a/app/atkbd.c b/app/atkbd.c index d450bc2..c12f70e 100644 --- a/app/atkbd.c +++ b/app/atkbd.c @@ -10,11 +10,11 @@ /*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 RESYNC_GAP (100 * MS) -#define ATKBD_TIMEOUT 1000 /*how long to wait for the keyboard to respond to a command in ms */ +#define ATKBD_TIMEOUT (1000 * MS) /*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_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 */ @@ -96,11 +96,22 @@ cycle_diff (uint32_t a, uint32_t b) return b - a; } + +static int fake_ctrl, pause_down; + +void +atkbd_dispatch_error (void) +{ + pause_down = 0; + fake_ctrl = 0; + scancode_error (); +} + + 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) { @@ -150,7 +161,7 @@ atkbd_data_dispatch (uint8_t byte) static int emul; #ifdef DEBUG - printf ("ATKBD < 0x%02x\r\n", byte); + printf ("ATKBD_RX < 0x%02x\r\n", byte); #endif switch (byte) @@ -162,6 +173,7 @@ atkbd_data_dispatch (uint8_t byte) atkbd_nack++; break; case ATKBD_RET_BAT: + atkbd_dispatch_error (); atkbd_bat++; break; case ATKBD_RET_ECHO: @@ -219,7 +231,16 @@ exti0_isr (void) atkbd_byte = 0; parity = 0; if (!d) - state++; + { + state++; + } + else + { + atkbd_dispatch_error (); +#ifdef DEBUG + printf ("ATKBD_ISR ! start bit non-zero\r\n"); +#endif + } break; case STATE_BIT0: case STATE_BIT1: @@ -236,8 +257,28 @@ exti0_isr (void) state++; break; case STATE_STOP: - if (d && parity) - atkbd_data_dispatch (atkbd_byte); + if (d) + { + if (parity) + atkbd_data_dispatch (atkbd_byte); + + if (!parity) + { + atkbd_dispatch_error (); +#ifdef DEBUG + printf ("ATKBD_ISR ! bad parity - issuing resend\r\n"); +#endif + atkbd_send (ATKBD_CMD_RESEND); + } + } + else + { + atkbd_dispatch_error (); +#ifdef DEBUG + printf ("ATKBD_ISR ! stop bit zero\r\n"); +#endif + } + state = STATE_START; break; } @@ -275,7 +316,7 @@ atkbd_set (int clk, int dat) int atkbd_send (uint8_t d) { - uint32_t then = ticks; + uint32_t then = dwt_read_cycle_counter ();; int parity = 1; uint32_t c; @@ -293,46 +334,46 @@ atkbd_send (uint8_t d) for (c = 1; c < 0x100; c <<= 1) { while (GET (KBCLK)) - if (timed_out (then, ATKBD_TIMEOUT)) + if (timed_out_cycles (then, ATKBD_TIMEOUT)) goto err; atkbd_set (1, c & d); parity ^= ! !(c & d); while (!GET (KBCLK)) - if (timed_out (then, ATKBD_TIMEOUT)) + if (timed_out_cycles (then, ATKBD_TIMEOUT)) goto err; } /* A parity bit */ while (GET (KBCLK)) - if (timed_out (then, ATKBD_TIMEOUT)) + if (timed_out_cycles (then, ATKBD_TIMEOUT)) goto err; atkbd_set (1, parity); while (!GET (KBCLK)) - if (timed_out (then, ATKBD_TIMEOUT)) + if (timed_out_cycles (then, ATKBD_TIMEOUT)) goto err; /* two stop bits */ while (GET (KBCLK)) - if (timed_out (then, ATKBD_TIMEOUT)) + if (timed_out_cycles (then, ATKBD_TIMEOUT)) goto err; atkbd_set (1, 1); while (!GET (KBCLK)) - if (timed_out (then, ATKBD_TIMEOUT)) + if (timed_out_cycles (then, ATKBD_TIMEOUT)) goto err; while (GET (KBCLK)) - if (timed_out (then, ATKBD_TIMEOUT)) + if (timed_out_cycles (then, ATKBD_TIMEOUT)) goto err; atkbd_set (1, 1); while (!GET (KBCLK)) - if (timed_out (then, ATKBD_TIMEOUT)) + if (timed_out_cycles (then, ATKBD_TIMEOUT)) goto err; while (!GET (KBDAT)) - if (timed_out (then, ATKBD_TIMEOUT)) + if (timed_out_cycles (then, ATKBD_TIMEOUT)) goto err; while (!GET (KBCLK)) - if (timed_out (then, ATKBD_TIMEOUT)) + if (timed_out_cycles (then, ATKBD_TIMEOUT)) goto err; atkbd_unmask_flush_irq (); @@ -346,10 +387,10 @@ atkbd_send (uint8_t d) err: atkbd_set (1, 1); while (!GET (KBDAT)) - if (timed_out (then, ATKBD_TIMEOUT)) + if (timed_out_cycles (then, ATKBD_TIMEOUT)) goto err; while (!GET (KBCLK)) - if (timed_out (then, ATKBD_TIMEOUT)) + if (timed_out_cycles (then, ATKBD_TIMEOUT)) goto err; atkbd_unmask_flush_irq (); @@ -363,18 +404,18 @@ err: static int atkbd_reset (void) { - uint32_t then = ticks; + uint32_t then = dwt_read_cycle_counter ();; atkbd_bat = 0; atkbd_send (ATKBD_CMD_RESET_BAT); while (!atkbd_bat) - if (timed_out (then, ATKBD_TIMEOUT)) + if (timed_out_cycles (then, ATKBD_TIMEOUT)) return -1; - then = ticks; + then = dwt_read_cycle_counter ();; atkbd_ack = 0; atkbd_send (ATKBD_CMD_SETALL_MBR); while (!atkbd_ack) - if (timed_out (then, ATKBD_TIMEOUT)) + if (timed_out_cycles (then, ATKBD_TIMEOUT)) return -1; @@ -384,11 +425,11 @@ atkbd_reset (void) int atkbd_request_echo (void) { - uint32_t then = ticks; + uint32_t then = dwt_read_cycle_counter ();; atkbd_ack = 0; atkbd_send (ATKBD_CMD_ECHO); while (!atkbd_echo) - if (timed_out (then, ATKBD_TIMEOUT)) + if (timed_out_cycles (then, ATKBD_TIMEOUT)) return -1; return 0; @@ -405,18 +446,18 @@ atkbd_set_leds (uint8_t leds) if (!ready) return 0; - then = ticks; + then = dwt_read_cycle_counter ();; atkbd_ack = 0; atkbd_send (ATKBD_CMD_SETLEDS); while (!atkbd_ack) - if (timed_out (then, ATKBD_TIMEOUT)) + if (timed_out_cycles (then, ATKBD_TIMEOUT)) return -1; - then = ticks; + then = dwt_read_cycle_counter ();; atkbd_ack = 0; atkbd_send (leds); while (!atkbd_ack) - if (timed_out (then, ATKBD_TIMEOUT)) + if (timed_out_cycles (then, ATKBD_TIMEOUT)) return -1; return 0; @@ -426,18 +467,18 @@ atkbd_set_leds (uint8_t leds) int atkbd_set_scanset (uint8_t scanset) { - uint32_t then = ticks; + uint32_t then = dwt_read_cycle_counter ();; atkbd_ack = 0; atkbd_send (ATKBD_CMD_SSCANSET); while (!atkbd_ack) - if (timed_out (then, ATKBD_TIMEOUT)) + if (timed_out_cycles (then, ATKBD_TIMEOUT)) return -1; - then = ticks; + then = dwt_read_cycle_counter ();; atkbd_ack = 0; atkbd_send (scanset); while (!atkbd_ack) - if (timed_out (then, ATKBD_TIMEOUT)) + if (timed_out_cycles (then, ATKBD_TIMEOUT)) return -1; return 0; @@ -446,11 +487,11 @@ atkbd_set_scanset (uint8_t scanset) int atkbd_set_mb (void) { - uint32_t then = ticks; + uint32_t then = dwt_read_cycle_counter ();; atkbd_ack = 0; atkbd_send (ATKBD_CMD_SETALL_MB); while (!atkbd_ack) - if (timed_out (then, ATKBD_TIMEOUT)) + if (timed_out_cycles (then, ATKBD_TIMEOUT)) return -1; return 0; @@ -459,11 +500,11 @@ atkbd_set_mb (void) int atkbd_set_mbr (void) { - uint32_t then = ticks; + uint32_t then = dwt_read_cycle_counter ();; atkbd_ack = 0; atkbd_send (ATKBD_CMD_SETALL_MBR); while (!atkbd_ack) - if (timed_out (then, ATKBD_TIMEOUT)) + if (timed_out_cycles (then, ATKBD_TIMEOUT)) return -1; return 0; @@ -477,9 +518,11 @@ atkbd_init (void) atkbd_set (1, 1); } -void atkbd_start(void) +void +atkbd_start (void) { - if (ready) return; + if (ready) + return; nvic_enable_irq (NVIC_EXTI0_IRQ); @@ -491,7 +534,7 @@ void atkbd_start(void) exti_reset_request (KBCLK); nvic_enable_irq (KBCLK_IRQ); - delay_ms(AT_KBD_INIT_TIME); + delay_ms (AT_KBD_INIT_TIME); atkbd_reset (); diff --git a/app/consumer.c b/app/consumer.c index 79d25bb..b1b6290 100644 --- a/app/consumer.c +++ b/app/consumer.c @@ -99,13 +99,15 @@ consumer_send (uint16_t keys) /*Last byte is the power wakeup stuff that we don't yet support */ uint8_t buf[CONSUMER_EP_TXN_SIZE] = { keys & 0xff, keys >> 8 }; - usbd_ep_write_packet (usbd_dev, CONSUMER_EP, buf, sizeof (buf)); + if (!usb_is_suspended) + usbd_ep_write_packet (usbd_dev, CONSUMER_EP, buf, sizeof (buf)); } +static uint16_t keys; + void consumer_dispatch (int bit, int updown) { - static uint16_t keys; if (updown) keys |= bit; @@ -117,7 +119,14 @@ consumer_dispatch (int bit, int updown) printf ("CNS> %02x %02x\r\n", keys & 0xff, keys >> 8); #endif - consumer_send (keys); + usb_wakeup_host(); + consumer_send (keys); +} +void +consumer_error (void) +{ + keys = 0; + consumer_send (keys); } diff --git a/app/keyboard.c b/app/keyboard.c index d35f466..f780ccc 100644 --- a/app/keyboard.c +++ b/app/keyboard.c @@ -127,19 +127,23 @@ keyboard_send (uint8_t modifiers, uint8_t * key_list) key_list[4], key_list[5], 0 }; - usbd_ep_write_packet (usbd_dev, KEYBOARD_EP, buf, sizeof (buf)); + if (!usb_is_suspended) + usbd_ep_write_packet (usbd_dev, KEYBOARD_EP, buf, sizeof (buf)); } +static uint8_t modifiers; +static uint8_t key_list[KEY_LIST_LEN]; + void keyboard_dispatch (int sc, int updown) { - static uint8_t modifiers; - static uint8_t key_list[KEY_LIST_LEN]; int i; /*Windows needs the modifiers spliting out, so we do this as per our * descriptor, others need them in the list so we do that as well */ + usb_wakeup_host(); + switch (sc) { case USB_K_SC_LEFTCTRL: @@ -156,6 +160,7 @@ keyboard_dispatch (int sc, int updown) modifiers &= ~(1 << (sc - USB_K_SC_LEFTCTRL)); break; default: + /* Some oses are picky and need these not to move about so we make * a list of the down keys */ @@ -195,6 +200,16 @@ keyboard_dispatch (int sc, int updown) } +void +keyboard_error (void) +{ + modifiers = 0; + memset (key_list, 0, sizeof (key_list)); + keyboard_send (modifiers, key_list); +} + + + int keyboard_control_request (usbd_device * usbd_dev, struct usb_setup_data *req, uint8_t ** buf, uint16_t * len, diff --git a/app/keymap.c b/app/keymap.c index d812911..5710237 100644 --- a/app/keymap.c +++ b/app/keymap.c @@ -129,6 +129,12 @@ static int at_to_usb_consumer[AT_SC_MAX] = { +void +scancode_error (void) +{ + keyboard_error (); + consumer_error (); +} void scancode_dispatch (int key, int updown) diff --git a/app/project.h b/app/project.h index 87363f9..e477856 100644 --- a/app/project.h +++ b/app/project.h @@ -14,6 +14,7 @@ #include #include +#include #include #include "ring.h" @@ -34,5 +35,8 @@ #define AT_KBD_INIT_TIME 200 +#define US (72) +#define MS ( US * 1000 ) + #include "prototypes.h" diff --git a/app/prototypes.h b/app/prototypes.h index 16aa300..1c692f8 100644 --- a/app/prototypes.h +++ b/app/prototypes.h @@ -9,12 +9,15 @@ extern const struct usb_endpoint_descriptor keyboard_endpoint; extern const struct usb_interface_descriptor keyboard_iface; extern void keyboard_get_descriptor(uint8_t **buf, uint16_t *len); extern void keyboard_dispatch(int sc, int updown); +extern void keyboard_error(void); extern int keyboard_control_request(usbd_device *usbd_dev, struct usb_setup_data *req, uint8_t **buf, uint16_t *len, void (**complete)(usbd_device *usbd_dev, struct usb_setup_data *req)); /* usb.c */ extern const struct usb_device_descriptor dev; extern const struct usb_interface ifaces[]; extern const struct usb_config_descriptor config; extern usbd_device *usbd_dev; +extern int usb_is_suspended; +extern int usb_wakeup_host(void); extern void usb_set_config(usbd_device *usbd_dev, uint16_t wValue); extern void usb_init(void); extern void usb_poll(void); @@ -24,7 +27,9 @@ extern const struct usb_endpoint_descriptor consumer_endpoint; extern const struct usb_interface_descriptor consumer_iface; extern void consumer_get_descriptor(uint8_t **buf, uint16_t *len); extern void consumer_dispatch(int bit, int updown); +extern void consumer_error(void); /* atkbd.c */ +extern void atkbd_dispatch_error(void); extern void exti0_isr(void); extern void atkbd_set(int clk, int dat); extern int atkbd_send(uint8_t d); @@ -63,6 +68,8 @@ extern void delay_us(uint32_t d); extern void sys_tick_handler(void); extern void delay_ms(uint32_t d); extern int timed_out(uint32_t then, unsigned int ms); +extern int timed_out_cycles(uint32_t then, unsigned int cycles); extern void ticker_init(void); /* keymap.c */ +extern void scancode_error(void); extern void scancode_dispatch(int key, int updown); diff --git a/app/ticker.c b/app/ticker.c index e3ff474..2c0d532 100644 --- a/app/ticker.c +++ b/app/ticker.c @@ -43,6 +43,17 @@ timed_out (uint32_t then, unsigned int ms) return 0; } +int +timed_out_cycles (uint32_t then, unsigned int cycles) +{ + then = dwt_read_cycle_counter () - then; + + if (then > cycles) + return 1; + return 0; +} + + void ticker_init (void) diff --git a/app/usb.c b/app/usb.c index 9d8c6f8..b03eb9c 100644 --- a/app/usb.c +++ b/app/usb.c @@ -59,6 +59,45 @@ static const char *usb_strings[] = { usbd_device *usbd_dev; +int usb_is_suspended = 1; + + +static void +usb_suspended (void) +{ + *USB_CNTR_REG |= USB_CNTR_FSUSP; + + usb_is_suspended = 1; +} + +static void +usb_resumed (void) +{ + + *USB_CNTR_REG &= ~USB_CNTR_FSUSP; + + usb_is_suspended = 0; +} + +int +usb_wakeup_host (void) +{ + if (!usb_is_suspended) + return 1; + + + *USB_CNTR_REG |= USB_CNTR_RESUME; + + delay_us (1000); + delay_us (1000); + delay_us (1000); + delay_us (1000); + delay_us (1000); + + *USB_CNTR_REG &= ~USB_CNTR_RESUME; + + return 0; +} static int usb_control_class_request (usbd_device * usbd_dev, struct usb_setup_data *req, @@ -139,6 +178,9 @@ usb_init (void) usbd_register_set_config_callback (usbd_dev, usb_set_config); + usbd_register_suspend_callback (usbd_dev, usb_suspended); + usbd_register_resume_callback (usbd_dev, usb_resumed); + } void -- cgit v1.2.3