]> git.friedersdorff.com Git - max/tmk_keyboard.git/blob - tmk_core/protocol/ibm4704.c
ibm4704_usb: Fix interrupt of clock(rising edge)
[max/tmk_keyboard.git] / tmk_core / protocol / ibm4704.c
1 /*
2 Copyright 2010,2011,2012,2013 Jun WAKO <wakojun@gmail.com>
3 */
4 #include <stdbool.h>
5 #include <util/delay.h>
6 #include "debug.h"
7 #include "ring_buffer.h"
8 #include "ibm4704.h"
9
10
11 #define WAIT(stat, us, err) do { \
12     if (!wait_##stat(us)) { \
13         ibm4704_error = err; \
14         goto ERROR; \
15     } \
16 } while (0)
17
18
19 uint8_t ibm4704_error = 0;
20
21
22 void ibm4704_init(void)
23 {
24     IBM4704_INT_INIT();
25     IBM4704_INT_ON();
26     idle();
27 }
28
29 /*
30 Host to Keyboard
31 ----------------
32 Data bits are LSB first and Parity is odd. Clock has around 60us high and 30us low part.
33
34         ____        __   __   __   __   __   __   __   __   __   ________
35 Clock       \______/  \_/  \_/  \_/  \_/  \_/  \_/  \_/  \_/  \_/
36             ^   ____ ____ ____ ____ ____ ____ ____ ____ ____ ____ ___
37 Data    ____|__/    X____X____X____X____X____X____X____X____X____X   \___
38             |  Start   0    1    2    3    4    5    6    7    P   Stop
39             Request by host
40
41 Start bit:  can be long as 300-350us.
42 Request:    Host pulls Clock line down to request to send a command.
43 Timing:     After Request keyboard pull up Data and down Clock line to low for start bit.
44             After request host release Clock line once Data line becomes hi.
45             Host writes a bit while Clock is hi and Keyboard reads while low.
46 Stop bit:   Host releases or pulls up Data line to hi after 9th clock and waits for keyboard pull down the line to lo.
47 */
48 uint8_t ibm4704_send(uint8_t data)
49 {
50     bool parity = true; // odd parity
51     ibm4704_error = 0;
52
53     IBM4704_INT_OFF();
54
55     /* Request to send */
56     idle();
57     clock_lo();
58
59     /* wait for Start bit(Clock:lo/Data:hi) */
60     WAIT(data_hi, 300, 0x30);
61
62     /* Data bit */
63     for (uint8_t i = 0; i < 8; i++) {
64         WAIT(clock_hi, 100, 0x40+i);
65         if (data&(1<<i)) {
66             parity = !parity;
67             data_hi();
68         } else {
69             data_lo();
70         }
71         WAIT(clock_lo, 100, 0x48+i);
72     }
73
74     /* Parity bit */
75     WAIT(clock_hi, 100, 0x34);
76     if (parity) { data_hi(); } else { data_lo(); }
77     WAIT(clock_lo, 100, 0x35);
78
79     /* Stop bit */
80     WAIT(clock_hi, 100, 0x34);
81     data_hi();
82
83     /* End */
84     WAIT(data_lo, 100, 0x36);
85
86     idle();
87     IBM4704_INT_ON();
88     return 0;
89 ERROR:
90     idle();
91     if (ibm4704_error > 0x30) {
92         xprintf("S:%02X ", ibm4704_error);
93     }
94     IBM4704_INT_ON();
95     return -1;
96 }
97
98 /* wait forever to receive data */
99 uint8_t ibm4704_recv_response(void)
100 {
101     while (!rbuf_has_data()) {
102         _delay_ms(1);
103     }
104     return rbuf_dequeue();
105 }
106
107 uint8_t ibm4704_recv(void)
108 {
109     if (rbuf_has_data()) {
110         return rbuf_dequeue();
111     } else {
112         return -1;
113     }
114 }
115
116 /*
117 Keyboard to Host
118 ----------------
119 Data bits are LSB first and Parity is odd. Clock has around 60us high and 30us low part.
120
121         ____       __   __   __   __   __   __   __   __   __   _______
122 Clock       \_____/  \_/  \_/  \_/  \_/  \_/  \_/  \_/  \_/  \_/
123              ____ ____ ____ ____ ____ ____ ____ ____ ____ ____    
124 Data    ____/    X____X____X____X____X____X____X____X____X____X________
125             Start   0    1    2    3    4    5    6    7    P  Stop
126
127 Start bit:  can be long as 300-350us.
128 Inhibit:    Pull Data line down to inhibit keyboard to send.
129 Timing:     Host reads bit while Clock is hi.(rising edge)
130 Stop bit:   Keyboard pulls down Data line to lo after 9th clock.
131 */
132 ISR(IBM4704_INT_VECT)
133 {
134     static enum {
135         STOP, BIT0, BIT1, BIT2, BIT3, BIT4, BIT5, BIT6, BIT7, PARITY
136     } state = STOP;
137     // LSB first
138     static uint8_t data = 0;
139     // Odd parity
140     static uint8_t parity = false;
141
142     ibm4704_error = 0;
143
144     switch (state++) {
145         case STOP:
146             // Data:Low
147             WAIT(data_lo, 10, state);
148             break;
149         case BIT0:
150         case BIT1:
151         case BIT2:
152         case BIT3:
153         case BIT4:
154         case BIT5:
155         case BIT6:
156         case BIT7:
157             data >>= 1;
158             if (data_in()) {
159                 data |= 0x80;
160                 parity = !parity;
161             }
162             break;
163         case PARITY:
164             if (data_in()) {
165                 parity = !parity;
166             }
167             if (!parity)
168                 goto ERROR;
169             rbuf_enqueue(data);
170             ibm4704_error = IBM4704_ERR_NONE;
171             goto DONE;
172             break;
173         default:
174             goto ERROR;
175     }
176     goto RETURN;
177 ERROR:
178     ibm4704_error = state;
179     while (ibm4704_send(0xFE)) _delay_ms(1); // resend
180     xprintf("R:%02X%02X\n", state, data);
181 DONE:
182     state = STOP;
183     data = 0;
184     parity = false;
185 RETURN:
186     return;
187 }