]> git.gir.st - tmk_keyboard.git/blob - protocol/ibm4704.c
Squashed 'tmk_core/' changes from b9e0ea0..caca2c0
[tmk_keyboard.git] / 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 /*
108 Keyboard to Host
109 ----------------
110 Data bits are LSB first and Parity is odd. Clock has around 60us high and 30us low part.
111
112 ____ __ __ __ __ __ __ __ __ __ ________
113 Clock \____/ \_/ \_/ \_/ \_/ \_/ \_/ \_/ \_/ \_/
114 ____ ____ ____ ____ ____ ____ ____ ____ ____ ____
115 Data ____/ X____X____X____X____X____X____X____X____X____X________
116 Start 0 1 2 3 4 5 6 7 P Stop
117
118 Start bit: can be long as 300-350us.
119 Inhibit: Pull Data line down to inhibit keyboard to send.
120 Timing: Host reads bit while Clock is hi.
121 Stop bit: Keyboard pulls down Data line to lo after 9th clock.
122 */
123 uint8_t ibm4704_recv(void)
124 {
125 if (rbuf_has_data()) {
126 return rbuf_dequeue();
127 } else {
128 return -1;
129 }
130 }
131
132 ISR(IBM4704_INT_VECT)
133 {
134 static enum {
135 INIT, START, BIT0, BIT1, BIT2, BIT3, BIT4, BIT5, BIT6, BIT7, PARITY,
136 } state = INIT;
137 // LSB first
138 static uint8_t data = 0;
139 // Odd parity
140 static uint8_t parity = false;
141
142 ibm4704_error = 0;
143 // return unless falling edge
144 if (clock_in()) { goto RETURN; } // why this occurs?
145
146 state++;
147 switch (state) {
148 case START:
149 // Data:Low
150 WAIT(data_hi, 10, state);
151 break;
152 case BIT0:
153 case BIT1:
154 case BIT2:
155 case BIT3:
156 case BIT4:
157 case BIT5:
158 case BIT6:
159 case BIT7:
160 data >>= 1;
161 if (data_in()) {
162 data |= 0x80;
163 parity = !parity;
164 }
165 break;
166 case PARITY:
167 if (data_in()) {
168 parity = !parity;
169 }
170 if (!parity)
171 goto ERROR;
172 rbuf_enqueue(data);
173 ibm4704_error = IBM4704_ERR_NONE;
174 goto DONE;
175 break;
176 default:
177 goto ERROR;
178 }
179 goto RETURN;
180 ERROR:
181 ibm4704_error = state;
182 while (ibm4704_send(0xFE)) _delay_ms(1); // resend
183 xprintf("R:%02X%02X\n", state, data);
184 DONE:
185 state = INIT;
186 data = 0;
187 parity = false;
188 RETURN:
189 return;
190 }
Imprint / Impressum