]> git.gir.st - tmk_keyboard.git/blob - m0110.c
Added protocol support for Macintosh keyboard M0110.
[tmk_keyboard.git] / m0110.c
1 /*
2 Copyright 2011 Jun WAKO <wakojun@gmail.com>
3
4 This software is licensed with a Modified BSD License.
5 All of this is supposed to be Free Software, Open Source, DFSG-free,
6 GPL-compatible, and OK to use in both free and proprietary applications.
7 Additions and corrections to this file are welcome.
8
9
10 Redistribution and use in source and binary forms, with or without
11 modification, are permitted provided that the following conditions are met:
12
13 * Redistributions of source code must retain the above copyright
14 notice, this list of conditions and the following disclaimer.
15
16 * Redistributions in binary form must reproduce the above copyright
17 notice, this list of conditions and the following disclaimer in
18 the documentation and/or other materials provided with the
19 distribution.
20
21 * Neither the name of the copyright holders nor the names of
22 contributors may be used to endorse or promote products derived
23 from this software without specific prior written permission.
24
25 THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
26 AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
27 IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
28 ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
29 LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
30 CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
31 SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
32 INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
33 CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
34 ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
35 POSSIBILITY OF SUCH DAMAGE.
36 */
37
38 #include <stdbool.h>
39 #include <avr/io.h>
40 #include <avr/interrupt.h>
41 #include <util/delay.h>
42 #include "m0110.h"
43 #include "debug.h"
44
45
46 static inline void clock_lo(void);
47 static inline void clock_hi(void);
48 static inline bool clock_in(void);
49 static inline void data_lo(void);
50 static inline void data_hi(void);
51 static inline bool data_in(void);
52 static inline uint16_t wait_clock_lo(uint16_t us);
53 static inline uint16_t wait_clock_hi(uint16_t us);
54 static inline uint16_t wait_data_lo(uint16_t us);
55 static inline uint16_t wait_data_hi(uint16_t us);
56 static inline void idle(void);
57 static inline void request(void);
58
59
60 /*
61 Primitive M0110 Library for AVR
62 ==============================
63
64
65 Signaling
66 ---------
67 CLOCK is always from KEYBOARD. DATA are sent with MSB first.
68
69 1) IDLE: both line is high.
70 CLOCK ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
71 DATA ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
72
73 2) KEYBOARD->HOST: HOST reads bit on rising edge.
74 CLOCK ~~~~~~~~~~~~|__|~~~|__|~~~|__|~~~|__|~~~|__|~~~|__|~~~|__|~~~|__|~~~~~~~~~~~
75 DATA ~~~~~~~~~~~~X777777X666666X555555X444444X333333X222222X111111X000000X~~~~~~~
76 <--> 160us(clock low)
77 <---> 180us(clock high)
78
79 3) HOST->KEYBOARD: HOST asserts bit on falling edge.
80 CLOCK ~~~~~~~~~~~~|__|~~~|__|~~~|__|~~~|__|~~~|__|~~~|__|~~~|__|~~~|__|~~~~~~~~~~~
81 DATA ~~~~~~|_____X777777X666666X555555X444444X333333X222222X111111X000000X~~~~~~~
82 <----> 840us(request to send by host) <-> 80us(hold DATA)
83 <--> 180us(clock low)
84 <---> 220us(clock high)
85
86
87 Protocol
88 --------
89 COMMAND:
90 Inquiry 0x10 get key event
91 Instant 0x12 get key event
92 Model 0x14 get model number(M0110 responds with 0x09)
93 bit 7 1 if another device connected(used when keypad exists?)
94 bit4-6 next device model number
95 bit1-3 keyboard model number
96 bit 0 always 1
97 Test 0x16 test(ACK:0x7D/NAK:0x77)
98
99 KEY EVENT:
100 bit 7 key state(0:press 1:release)
101 bit 6-1 scan code
102 bit 0 always 1
103 To get scan code, use ((bits&(1<<7)) | ((bits&7F))>>1).
104
105 SCAN CODE:
106 M0110A
107 ,---------------------------------------------------------.
108 | `| 1| 2| 3| 4| 5| 6| 7| 8| 9| 0| -| =|Backs|
109 |---------------------------------------------------------|
110 |Tab | Q| W| E| R| T| Y| U| I| O| P| [| ]| \|
111 |---------------------------------------------------------|
112 |CapsLo| A| S| D| F| G| H| J| K| L| ;| '|Return|
113 |---------------------------------------------------------|
114 |Shift | Z| X| C| V| B| N| M| ,| ,| /| |
115 `---------------------------------------------------------'
116 |Opt|Mac | Space |Enter|Opt|
117 `------------------------------------------------'
118 ,---------------------------------------------------------.
119 | 32| 12| 13| 14| 15| 17| 16| 1A| 1C| 19| 1D| 1B| 18| 33|
120 |---------------------------------------------------------|
121 | 30| 0C| 0D| 0E| 0F| 10| 11| 20| 22| 1F| 23| 21| 1E| 2A|
122 |---------------------------------------------------------|
123 | 39| 00| 01| 02| 03| 05| 04| 26| 28| 25| 29| 27| 24|
124 |---------------------------------------------------------|
125 | 38| 06| 07| 08| 09| 0B| 2D| 2E| 2B| 2F| 2C| 38|
126 `---------------------------------------------------------'
127 | 3A| 37| 31 | 34| 3A|
128 `------------------------------------------------'
129
130
131 References
132 ----------
133 Protocol:
134 http://www.mac.linux-m68k.org/devel/plushw.php
135 Connector:
136 http://www.kbdbabel.org/conn/kbd_connector_macplus.png
137 Signaling:
138 http://www.kbdbabel.org/signaling/kbd_signaling_mac.png
139 http://typematic.blog.shinobi.jp/Entry/14/
140 Scan Codes:
141 http://m0115.web.fc2.com/m0110.jpg
142 http://m0115.web.fc2.com/m0110a.jpg
143 */
144
145
146 #define WAIT(stat, us, err) do { \
147 if (!wait_##stat(us)) { \
148 m0110_error = err; \
149 goto ERROR; \
150 } \
151 } while (0)
152
153
154 uint8_t m0110_error = 0;
155
156
157 void m0110_init(void)
158 {
159 uint8_t data;
160 idle();
161 _delay_ms(255);
162
163 m0110_send(M0110_MODLE);
164 data = m0110_recv();
165 print("m0110_init model: "); phex(data); print("\n");
166
167 m0110_send(M0110_TEST);
168 data = m0110_recv();
169 print("m0110_init test: "); phex(data); print("\n");
170 }
171
172 uint8_t m0110_send(uint8_t data)
173 {
174 m0110_error = 0;
175
176 request();
177 WAIT(clock_lo, 1000, 0);
178 for (uint8_t bit = 0x80; bit; bit >>= 1) {
179 WAIT(clock_lo, 250, 3);
180 _delay_us(15);
181 if (data&bit) {
182 data_hi();
183 } else {
184 data_lo();
185 }
186 WAIT(clock_hi, 200, 4);
187 }
188 _delay_us(100); // hold last bit for 80us
189 idle();
190 return 1;
191 ERROR:
192 if (m0110_error) {
193 print("m0110_send err: "); phex(m0110_error); print("\n");
194 }
195 idle();
196 return 0;
197 }
198
199 uint8_t m0110_recv(void)
200 {
201 uint8_t data = 0;
202 m0110_error = 0;
203
204 WAIT(clock_lo, -1, 0); // need 250ms? insted 0xffff(16bit max)us
205 for (uint8_t i = 0; i < 8; i++) {
206 data <<= 1;
207 WAIT(clock_lo, 200, 2);
208 WAIT(clock_hi, 200, 3);
209 if (data_in()) {
210 data |= 1;
211 }
212 }
213 idle();
214 print("m0110_send recv data: "); phex(data); print("\n");
215 return data;
216 ERROR:
217 if (m0110_error) {
218 print("m0110_recv err: "); phex(m0110_error); print("\n");
219 }
220 idle();
221 return 0xFF;
222 }
223
224 uint8_t m0110_recv_key(void)
225 {
226 uint8_t key;
227 m0110_send(M0110_INQUIRY);
228 key = m0110_recv();
229 if (key == 0xFF || key == M0110_NULL)
230 return M0110_NULL;
231 else
232 return (key&(1<<7) | (key&0x7F)>>1);
233 }
234
235
236 static inline void clock_lo()
237 {
238 M0110_CLOCK_PORT &= ~(1<<M0110_CLOCK_BIT);
239 M0110_CLOCK_DDR |= (1<<M0110_CLOCK_BIT);
240 }
241 static inline void clock_hi()
242 {
243 /* input with pull up */
244 M0110_CLOCK_DDR &= ~(1<<M0110_CLOCK_BIT);
245 M0110_CLOCK_PORT |= (1<<M0110_CLOCK_BIT);
246 }
247 static inline bool clock_in()
248 {
249 M0110_CLOCK_DDR &= ~(1<<M0110_CLOCK_BIT);
250 M0110_CLOCK_PORT |= (1<<M0110_CLOCK_BIT);
251 _delay_us(1);
252 return M0110_CLOCK_PIN&(1<<M0110_CLOCK_BIT);
253 }
254 static inline void data_lo()
255 {
256 M0110_DATA_PORT &= ~(1<<M0110_DATA_BIT);
257 M0110_DATA_DDR |= (1<<M0110_DATA_BIT);
258 }
259 static inline void data_hi()
260 {
261 /* input with pull up */
262 M0110_DATA_DDR &= ~(1<<M0110_DATA_BIT);
263 M0110_DATA_PORT |= (1<<M0110_DATA_BIT);
264 }
265 static inline bool data_in()
266 {
267 M0110_DATA_DDR &= ~(1<<M0110_DATA_BIT);
268 M0110_DATA_PORT |= (1<<M0110_DATA_BIT);
269 _delay_us(1);
270 return M0110_DATA_PIN&(1<<M0110_DATA_BIT);
271 }
272
273 static inline uint16_t wait_clock_lo(uint16_t us)
274 {
275 while (clock_in() && us) { asm(""); _delay_us(1); us--; }
276 return us;
277 }
278 static inline uint16_t wait_clock_hi(uint16_t us)
279 {
280 while (!clock_in() && us) { asm(""); _delay_us(1); us--; }
281 return us;
282 }
283 static inline uint16_t wait_data_lo(uint16_t us)
284 {
285 while (data_in() && us) { asm(""); _delay_us(1); us--; }
286 return us;
287 }
288 static inline uint16_t wait_data_hi(uint16_t us)
289 {
290 while (!data_in() && us) { asm(""); _delay_us(1); us--; }
291 return us;
292 }
293
294 static inline void idle(void)
295 {
296 clock_hi();
297 data_hi();
298 }
299
300 static inline void request(void)
301 {
302 clock_hi();
303 data_lo();
304 }
Imprint / Impressum