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