]> git.gir.st - tmk_keyboard.git/blob - tmk_core/protocol/ibm4704.c
Add keyboard_setup() and matrix_setup()
[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 }
Imprint / Impressum