]> git.friedersdorff.com Git - max/tmk_keyboard.git/blobdiff - ps2.c
added initial V-USB support for HHKB
[max/tmk_keyboard.git] / ps2.c
diff --git a/ps2.c b/ps2.c
index 6d76538fe4c0b7fb01e1bba26a00d25c9c669eb1..d5c3d4d4e17f4f96dfdc063b68255fa8d04bdc04 100644 (file)
--- a/ps2.c
+++ b/ps2.c
@@ -96,13 +96,15 @@ void ps2_host_init(void)
 #endif
 }
 
+// TODO: send using interrupt if available
 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 */
     inhibit();
     _delay_us(100);
@@ -139,15 +141,15 @@ RETRY:
     WAIT(clock_hi, 50, 8);
     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:
+#ifdef PS2_INT_ENABLE
+    PS2_INT_ENABLE();
+    idle();
+#else
     inhibit();
-    return 0;
+#endif
+    return res;
 }
 
 /* receive data when host want else inhibit communication */
@@ -185,6 +187,9 @@ static inline void pbuf_enqueue(uint8_t data)
 {
     if (!data)
         return;
+
+    uint8_t sreg = SREG;
+    cli();
     uint8_t next = (pbuf_head + 1) % PBUF_SIZE;
     if (next != pbuf_tail) {
         pbuf[pbuf_head] = data;
@@ -192,10 +197,12 @@ static inline void pbuf_enqueue(uint8_t data)
     } else {
         debug("pbuf: full\n");
     }
+    SREG = sreg;
 }
 static inline uint8_t pbuf_dequeue(void)
 {
     uint8_t val = 0;
+
     uint8_t sreg = SREG;
     cli();
     if (pbuf_head != pbuf_tail) {
@@ -203,52 +210,113 @@ static inline uint8_t pbuf_dequeue(void)
         pbuf_tail = (pbuf_tail + 1) % PBUF_SIZE;
     }
     SREG = sreg;
+
     return val;
 }
 
 /* get data received by interrupt */
 uint8_t ps2_host_recv(void)
 {
+    if (ps2_error) {
+        print("x");
+        phex(ps2_error);
+        ps2_host_send(0xFE);    // request to resend
+        ps2_error = PS2_ERR_NONE;
+    }
+    idle();
     return pbuf_dequeue();
 }
 
+#if 0
+#define DEBUGP_INIT() do { DDRC = 0xFF; } while (0)
+#define DEBUGP(x) do { PORTC = x; } while (0)
+#else
+#define DEBUGP_INIT()
+#define DEBUGP(x)
+#endif
 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(0x0F);
+    inhibit();
+    ps2_error = state;
+DONE:
+    state = INIT;
+    data = 0;
+    parity = 1;
+RETURN:
+    return;
 }
 #endif
 
 
-/*
 static void ps2_reset(void)
 {
     ps2_host_send(0xFF);
-    if (ps2_host_recv_response() == 0xFA) {
-        _delay_ms(1000);
-        ps2_host_recv_response();
-    }
 }
-*/
 
 /* send LED state to keyboard */
 void ps2_host_set_led(uint8_t led)
 {
-#ifdef PS2_INT_DISABLE
-    PS2_INT_DISABLE();
-#endif
     ps2_host_send(0xED);
-    ps2_host_recv_response();
     ps2_host_send(led);
-    ps2_host_recv_response();
-#ifdef PS2_INT_ENABLE
-    PS2_INT_ENABLE();
-    idle();
-#endif
 }
 
 
@@ -257,7 +325,7 @@ static uint8_t recv_data(void)
 {
     uint8_t data = 0;
     bool parity = true;
-    ps2_error = 0;
+    ps2_error = PS2_ERR_NONE;
 
     /* start bit [1] */
     WAIT(clock_lo, 1, 1);
@@ -307,6 +375,7 @@ static inline bool clock_in()
 {
     PS2_CLOCK_DDR  &= ~(1<<PS2_CLOCK_BIT);
     PS2_CLOCK_PORT |=  (1<<PS2_CLOCK_BIT);
+    _delay_us(1);
     return PS2_CLOCK_PIN&(1<<PS2_CLOCK_BIT);
 }
 static inline void data_lo()
@@ -324,6 +393,7 @@ static inline bool data_in()
 {
     PS2_DATA_DDR  &= ~(1<<PS2_DATA_BIT);
     PS2_DATA_PORT |=  (1<<PS2_DATA_BIT);
+    _delay_us(1);
     return PS2_DATA_PIN&(1<<PS2_DATA_BIT);
 }