]> git.friedersdorff.com Git - max/tmk_keyboard.git/blobdiff - tmk_core/protocol/ibmpc.c
usb_hid: Update arduino cores to 1.8.13
[max/tmk_keyboard.git] / tmk_core / protocol / ibmpc.c
index 6fb949e7dfe0fe54094af13d410d17e6a174673e..5f2ca79b2fba9f1bd8067b46ed1d2ca8ca6044a1 100644 (file)
@@ -56,15 +56,17 @@ POSSIBILITY OF SUCH DAMAGE.
 } while (0)
 
 
+volatile uint16_t ibmpc_isr_debug = 0;
 volatile uint8_t ibmpc_protocol = IBMPC_PROTOCOL_NO;
 volatile uint8_t ibmpc_error = IBMPC_ERR_NONE;
 
-/* 2-byte buffer for data received from keyhboard
+/* 2-byte buffer for data received from keyboard
  * buffer states:
  *      FFFF: empty
  *      FFss: one data
- *      sstt: two data(full)
- *  0xFF can not be stored as data in buffer because it means empty or no data.
+ *      sstt: two data
+ *      eeFF: error
+ * where ss, tt and ee are 0x00-0xFE. 0xFF means empty or no data in buffer.
  */
 static volatile uint16_t recv_data = 0xFFFF;
 /* internal state of receiving data */
@@ -103,12 +105,13 @@ int16_t ibmpc_host_send(uint8_t data)
 
     /* terminate a transmission if we have */
     inhibit();
-    wait_us(100); // 100us [4]p.13, [5]p.50
+    wait_us(100);    // [5]p.54
 
     /* 'Request to Send' and Start bit */
     data_lo();
-    clock_hi();
-    WAIT(clock_lo, 10000, 1);   // 10ms [5]p.50
+    wait_us(100);
+    clock_hi();     // [5]p.54 [clock low]>100us [5]p.50
+    WAIT(clock_lo, 10000, 1);   // [5]p.53, -10ms [5]p.50
 
     /* Data bit[2-9] */
     for (uint8_t i = 0; i < 8; i++) {
@@ -132,14 +135,15 @@ int16_t ibmpc_host_send(uint8_t data)
     /* Stop bit */
     wait_us(15);
     data_hi();
+    WAIT(clock_hi, 50, 6);
+    WAIT(clock_lo, 50, 7);
 
     /* Ack */
-    WAIT(data_lo, 50, 6);
-    WAIT(clock_lo, 50, 7);
+    WAIT(data_lo, 50, 8);
 
     /* wait for idle state */
-    WAIT(clock_hi, 50, 8);
-    WAIT(data_hi, 50, 9);
+    WAIT(clock_hi, 50, 9);
+    WAIT(data_hi, 50, 10);
 
     // clear buffer to get response correctly
     recv_data = 0xFFFF;
@@ -165,19 +169,50 @@ int16_t ibmpc_host_recv(void)
 
     ATOMIC_BLOCK(ATOMIC_RESTORESTATE) {
         data = recv_data;
-        if ((data&0xFF00) != 0xFF00) {      // recv_data:sstt -> recv_data:FFtt, ret:ss
-            ret = (data>>8)&0x00FF;
-            recv_data = data | 0xFF00;
-        } else if (data != 0xFFFF) {        // recv_data:FFss -> recv_data:FFFF, ret:ss
-            ret = data&0x00FF;
-            recv_data = data | 0x00FF;
-        }
+
+        // remove data from buffer:
+        // FFFF(empty)      -> FFFF
+        // FFss(one data)   -> FFFF
+        // sstt(two data)   -> FFtt
+        // eeFF(errror)     -> FFFF
+        recv_data = data | (((data&0xFF00) == 0xFF00) ? 0x00FF : 0xFF00);
     }
 
-    if ((data | 0x00FF) != 0xFFFF) dprintf("b%04X ", data);
-    if (ret != 0xFF) dprintf("r%02X ", ret);
-    return ((ret != 0xFF) ? ret : -1);
+    if ((data&0x00FF) == 0x00FF) {
+        // error: eeFF
+        switch (data>>8) {
+            case IBMPC_ERR_FF:
+                // 0xFF(Overrun/Error) from keyboard
+                dprintf("!FF! ");
+                ret = 0xFF;
+                break;
+            case IBMPC_ERR_FULL:
+                // buffer full
+                dprintf("!FULL! ");
+                ret = 0xFF;
+                break;
+            case 0xFF:
+                // empty: FFFF
+                return -1;
+            default:
+                // other errors
+                dprintf("e%02X ", data>>8);
+                return -1;
+        }
+    } else {
+        if ((data | 0x00FF) != 0xFFFF) {
+            // two data: sstt
+            dprintf("b:%04X ", data);
+            ret = (data>>8);
+        } else {
+            // one data: FFss
+            ret = (data&0x00FF);
+        }
+    }
 
+    //dprintf("i%04X ", ibmpc_isr_debug); ibmpc_isr_debug = 0;
+    dprintf("r%02X ", ret);
+    return ret;
 }
 
 int16_t ibmpc_host_recv_response(void)
@@ -193,10 +228,15 @@ int16_t ibmpc_host_recv_response(void)
 
 void ibmpc_host_isr_clear(void)
 {
+    ibmpc_isr_debug = 0;
+    ibmpc_protocol = 0;
+    ibmpc_error = 0;
     isr_state = 0x8000;
     recv_data = 0xFFFF;
 }
 
+#define LO8(w)  (*((uint8_t *)&(w)))
+#define HI8(w)  (*(((uint8_t *)&(w))+1))
 // NOTE: With this ISR data line can be read within 2us after clock falling edge.
 // To read data line early as possible:
 // write naked ISR with asembly code to read the line and call C func to do other job?
@@ -213,13 +253,16 @@ ISR(IBMPC_INT_VECT)
     if (isr_state == 0x8000) {
         timer_start = t;
     } else {
-        // should not take more than 1ms
-        if (timer_start != t && (uint8_t)(timer_start + 1) != t) {
+        // This gives 2.0ms at least before timeout
+        if ((uint8_t)(t - timer_start) >= 3) {
+            ibmpc_isr_debug = isr_state;
             ibmpc_error = IBMPC_ERR_TIMEOUT;
-            //goto ERROR;
-            // timeout error recovery by clearing isr_state?
-            timer_start = t;
-            isr_state = 0x8000;
+            goto ERROR;
+
+            // timeout error recovery - start receiving new data
+            // it seems to work somehow but may not under unstable situation
+            //timer_start = t;
+            //isr_state = 0x8000;
         }
     }
 
@@ -244,10 +287,12 @@ ISR(IBMPC_INT_VECT)
     //       x  x  x  x    x  x  x  x | *1  0  0  0    0  0  0  0     midway(8 bits received)
     //      b6 b5 b4 b3   b2 b1 b0  1 |  0 *1  0  0    0  0  0  0     XT_IBM-midway ^1
     //      b7 b6 b5 b4   b3 b2 b1 b0 |  0 *1  0  0    0  0  0  0     AT-midway ^1
-    //      b7 b6 b5 b4   b3 b2 b1 b0 |  1 *1  0  0    0  0  0  0     XT_Clone-done
+    //      b7 b6 b5 b4   b3 b2 b1 b0 |  1 *1  0  0    0  0  0  0     XT_Clone-done ^3
+    //      b6 b5 b4 b3   b2 b1 b0  1 |  1 *1  0  0    0  0  0  0     XT_IBM-error ^3
     //      pr b7 b6 b5   b4 b3 b2 b1 |  0  0 *1  0    0  0  0  0     AT-midway[b0=0]
     //      b7 b6 b5 b4   b3 b2 b1 b0 |  1  0 *1  0    0  0  0  0     XT_IBM-done ^2
     //      pr b7 b6 b5   b4 b3 b2 b1 |  1  0 *1  0    0  0  0  0     AT-midway[b0=1] ^2
+    //      b7 b6 b5 b4   b3 b2 b1 b0 |  1  1 *1  0    0  0  0  0     XT_IBM-error-done
     //       x  x  x  x    x  x  x  x |  x  1  1  0    0  0  0  0     illegal
     //      st pr b7 b6   b5 b4 b3 b2 | b1 b0  0 *1    0  0  0  0     AT-done
     //       x  x  x  x    x  x  x  x |  x  x  1 *1    0  0  0  0     illegal
@@ -264,10 +309,30 @@ ISR(IBMPC_INT_VECT)
             // midway
             goto NEXT;
             break;
-        case 0b11000000:
-            // XT_Clone-done
+        case 0b11000000:    // ^3
+            {
+                uint8_t us = 100;
+                // wait for rising and falling edge of b7 of XT_IBM
+                while (!(IBMPC_CLOCK_PIN&(1<<IBMPC_CLOCK_BIT)) && us) { wait_us(1); us--; }
+                while (  IBMPC_CLOCK_PIN&(1<<IBMPC_CLOCK_BIT)  && us) { wait_us(1); us--; }
+
+                if (us) {
+                    // XT_IBM-error: read start(0) as 1
+                    goto NEXT;
+                } else {
+                    // XT_Clone-done
+                    ibmpc_isr_debug = isr_state;
+                    isr_state = isr_state>>8;
+                    ibmpc_protocol = IBMPC_PROTOCOL_XT_CLONE;
+                    goto DONE;
+                }
+            }
+            break;
+        case 0b11100000:
+            // XT_IBM-error-done
+            ibmpc_isr_debug = isr_state;
             isr_state = isr_state>>8;
-            ibmpc_protocol = IBMPC_PROTOCOL_XT_CLONE;
+            ibmpc_protocol = IBMPC_PROTOCOL_XT_ERROR;
             goto DONE;
             break;
         case 0b10100000:    // ^2
@@ -282,6 +347,7 @@ ISR(IBMPC_INT_VECT)
                     goto NEXT;
                 } else {
                     // no stop bit: XT_IBM-done
+                    ibmpc_isr_debug = isr_state;
                     isr_state = isr_state>>8;
                     ibmpc_protocol = IBMPC_PROTOCOL_XT_IBM;
                     goto DONE;
@@ -294,39 +360,52 @@ ISR(IBMPC_INT_VECT)
         case 0b11010000:
             // AT-done
             // TODO: parity check?
+            ibmpc_isr_debug = isr_state;
+            // stop bit check
+            if (isr_state & 0x8000) {
+                ibmpc_protocol = IBMPC_PROTOCOL_AT;
+            } else {
+                // Zenith Z-150 AT(beige/white lable) asserts stop bit as low
+                // https://github.com/tmk/tmk_keyboard/wiki/IBM-PC-AT-Keyboard-Protocol#zenith-z-150-beige
+                ibmpc_protocol = IBMPC_PROTOCOL_AT_Z150;
+            }
             isr_state = isr_state>>6;
-            ibmpc_protocol = IBMPC_PROTOCOL_AT;
             goto DONE;
             break;
         case 0b01100000:
-        case 0b11100000:
         case 0b00110000:
         case 0b10110000:
         case 0b01110000:
         case 0b11110000:
         default:            // xxxx_oooo(any 1 in low nibble)
             // Illegal
+            ibmpc_isr_debug = isr_state;
             ibmpc_error = IBMPC_ERR_ILLEGAL;
             goto ERROR;
             break;
     }
 
 ERROR:
-    isr_state = 0x8000;
-    recv_data = 0xFF00; // clear data and scancode of error 0x00
-    return;
+    // error: eeFF
+    recv_data = (ibmpc_error<<8) | 0x00FF;
+    goto CLEAR;
 DONE:
     if ((isr_state & 0x00FF) == 0x00FF) {
         // receive error code 0xFF
         ibmpc_error = IBMPC_ERR_FF;
+        goto ERROR;
     }
-    if ((recv_data & 0xFF00) != 0xFF00) {
-        // buffer full and overwritten
+    if (HI8(recv_data) != 0xFF && LO8(recv_data) != 0xFF) {
+        // buffer full
         ibmpc_error = IBMPC_ERR_FULL;
+        goto ERROR;
     }
+    // store data
     recv_data = recv_data<<8;
     recv_data |= isr_state & 0xFF;
-    isr_state = 0x8000;  // clear to next data
+CLEAR:
+    // clear for next data
+    isr_state = 0x8000;
 NEXT:
     return;
 }
@@ -334,6 +413,7 @@ NEXT:
 /* send LED state to keyboard */
 void ibmpc_host_set_led(uint8_t led)
 {
-    ibmpc_host_send(0xED);
-    ibmpc_host_send(led);
+    if (0xFA == ibmpc_host_send(0xED)) {
+        ibmpc_host_send(led);
+    }
 }