]> git.gir.st - tmk_keyboard.git/blob - m0110.c
Fix bug on RAW2SCAN. Add work around for M0110A.
[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 /* M0110A Support was contributed by skagon@github */
38
39 #include <stdbool.h>
40 #include <avr/io.h>
41 #include <avr/interrupt.h>
42 #include <util/delay.h>
43 #include "m0110.h"
44 #include "debug.h"
45
46
47 static inline uint8_t raw2scan(uint8_t raw);
48 static inline uint8_t inquiry(void);
49 static inline uint8_t instant(void);
50 static inline void clock_lo(void);
51 static inline void clock_hi(void);
52 static inline bool clock_in(void);
53 static inline void data_lo(void);
54 static inline void data_hi(void);
55 static inline bool data_in(void);
56 static inline uint16_t wait_clock_lo(uint16_t us);
57 static inline uint16_t wait_clock_hi(uint16_t us);
58 static inline uint16_t wait_data_lo(uint16_t us);
59 static inline uint16_t wait_data_hi(uint16_t us);
60 static inline void idle(void);
61 static inline void request(void);
62
63
64 #define WAIT_US(stat, us, err) do { \
65 if (!wait_##stat(us)) { \
66 m0110_error = err; \
67 goto ERROR; \
68 } \
69 } while (0)
70
71 #define WAIT_MS(stat, ms, err) do { \
72 uint16_t _ms = ms; \
73 while (_ms) { \
74 if (wait_##stat(1000)) { \
75 break; \
76 } \
77 _ms--; \
78 } \
79 if (_ms == 0) { \
80 m0110_error = err; \
81 goto ERROR; \
82 } \
83 } while (0)
84
85
86 uint8_t m0110_error = 0;
87
88
89 void m0110_init(void)
90 {
91 uint8_t data;
92 idle();
93 _delay_ms(1000);
94
95 // Model Number
96 // M0110 : 0x09 00001001 : model number 4 (100)
97 // M0110A: 0x0B 00001011 : model number 5 (101)
98 // M0110 & M0120: ???
99 m0110_send(M0110_MODEL);
100 data = m0110_recv();
101 print("m0110_init model: "); phex(data); print("\n");
102
103 m0110_send(M0110_TEST);
104 data = m0110_recv();
105 print("m0110_init test: "); phex(data); print("\n");
106 }
107
108 uint8_t m0110_send(uint8_t data)
109 {
110 m0110_error = 0;
111
112 request();
113 WAIT_MS(clock_lo, 250, 1); // keyboard may block long time
114 for (uint8_t bit = 0x80; bit; bit >>= 1) {
115 WAIT_US(clock_lo, 250, 3);
116 if (data&bit) {
117 data_hi();
118 } else {
119 data_lo();
120 }
121 WAIT_US(clock_hi, 200, 4);
122 }
123 _delay_us(100); // hold last bit for 80us
124 idle();
125 return 1;
126 ERROR:
127 print("m0110_send err: "); phex(m0110_error); print("\n");
128 _delay_ms(500);
129 idle();
130 return 0;
131 }
132
133 uint8_t m0110_recv(void)
134 {
135 uint8_t data = 0;
136 m0110_error = 0;
137
138 WAIT_MS(clock_lo, 250, 1); // keyboard may block long time
139 for (uint8_t i = 0; i < 8; i++) {
140 data <<= 1;
141 WAIT_US(clock_lo, 200, 2);
142 WAIT_US(clock_hi, 200, 3);
143 if (data_in()) {
144 data |= 1;
145 }
146 }
147 idle();
148 return data;
149 ERROR:
150 print("m0110_recv err: "); phex(m0110_error); print("\n");
151 _delay_ms(500);
152 idle();
153 return 0xFF;
154 }
155
156 uint8_t m0110_recv_key(void)
157 {
158 static uint8_t keybuf = 0x00;
159 uint8_t key, key2, key3;
160
161 if (keybuf) {
162 key = keybuf;
163 keybuf = 0x00;
164 return key;
165 }
166 key = instant(); // Use INSTANT for better response. Should be INQUIRY ?
167 switch (key & 0x7F) {
168 case M0110_KEYPAD:
169 // Pad/Arrow keys
170 return (raw2scan(instant()) | M0110_KEYPAD_OFFSET);
171 break;
172 case M0110_SHIFT:
173 key2 = instant();
174 if (key2 == M0110_KEYPAD) {
175 key3 = instant();
176 switch (key3 & 0x7F) {
177 case M0110_ARROW_UP:
178 case M0110_ARROW_DOWN:
179 case M0110_ARROW_LEFT:
180 case M0110_ARROW_RIGHT:
181 // Calc keys
182 return (raw2scan(key3) | M0110_CALC_OFFSET);
183 default:
184 // Shift + Pad/Arrow keys
185 keybuf = raw2scan(key3);
186 return (raw2scan(key) | M0110_KEYPAD_OFFSET);
187 }
188 } else {
189 // Shift + other keys
190 keybuf = raw2scan(key2);
191 return raw2scan(key);
192 }
193 break;
194 default:
195 // other keys
196 return raw2scan(key);
197 break;
198 }
199 }
200
201
202 static inline uint8_t raw2scan(uint8_t raw) {
203 return (raw == M0110_NULL) ? M0110_NULL : (
204 (raw == M0110_ERROR) ? M0110_ERROR : (
205 ((raw&0x80) | ((raw&0x7F)>>1))
206 )
207 );
208 }
209
210 static inline uint8_t inquiry(void)
211 {
212 m0110_send(M0110_INQUIRY);
213 return m0110_recv();
214 }
215
216 static inline uint8_t instant(void)
217 {
218 m0110_send(M0110_INSTANT);
219 //return m0110_recv();
220 uint8_t data = m0110_recv();
221 if (data != 0x7B) {
222 print("data: "); phex(data); print("\n");
223 }
224 return data;
225 }
226
227 static inline void clock_lo()
228 {
229 M0110_CLOCK_PORT &= ~(1<<M0110_CLOCK_BIT);
230 M0110_CLOCK_DDR |= (1<<M0110_CLOCK_BIT);
231 }
232 static inline void clock_hi()
233 {
234 /* input with pull up */
235 M0110_CLOCK_DDR &= ~(1<<M0110_CLOCK_BIT);
236 M0110_CLOCK_PORT |= (1<<M0110_CLOCK_BIT);
237 }
238 static inline bool clock_in()
239 {
240 M0110_CLOCK_DDR &= ~(1<<M0110_CLOCK_BIT);
241 M0110_CLOCK_PORT |= (1<<M0110_CLOCK_BIT);
242 _delay_us(1);
243 return M0110_CLOCK_PIN&(1<<M0110_CLOCK_BIT);
244 }
245 static inline void data_lo()
246 {
247 M0110_DATA_PORT &= ~(1<<M0110_DATA_BIT);
248 M0110_DATA_DDR |= (1<<M0110_DATA_BIT);
249 }
250 static inline void data_hi()
251 {
252 /* input with pull up */
253 M0110_DATA_DDR &= ~(1<<M0110_DATA_BIT);
254 M0110_DATA_PORT |= (1<<M0110_DATA_BIT);
255 }
256 static inline bool data_in()
257 {
258 M0110_DATA_DDR &= ~(1<<M0110_DATA_BIT);
259 M0110_DATA_PORT |= (1<<M0110_DATA_BIT);
260 _delay_us(1);
261 return M0110_DATA_PIN&(1<<M0110_DATA_BIT);
262 }
263
264 static inline uint16_t wait_clock_lo(uint16_t us)
265 {
266 while (clock_in() && us) { asm(""); _delay_us(1); us--; }
267 return us;
268 }
269 static inline uint16_t wait_clock_hi(uint16_t us)
270 {
271 while (!clock_in() && us) { asm(""); _delay_us(1); us--; }
272 return us;
273 }
274 static inline uint16_t wait_data_lo(uint16_t us)
275 {
276 while (data_in() && us) { asm(""); _delay_us(1); us--; }
277 return us;
278 }
279 static inline uint16_t wait_data_hi(uint16_t us)
280 {
281 while (!data_in() && us) { asm(""); _delay_us(1); us--; }
282 return us;
283 }
284
285 static inline void idle(void)
286 {
287 clock_hi();
288 data_hi();
289 }
290
291 static inline void request(void)
292 {
293 clock_hi();
294 data_lo();
295 }
296
297
298
299 /*
300 Primitive M0110 Library for AVR
301 ==============================
302
303
304 Signaling
305 ---------
306 CLOCK is always from KEYBOARD. DATA are sent with MSB first.
307
308 1) IDLE: both lines are high.
309 CLOCK ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
310 DATA ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
311
312 2) KEYBOARD->HOST: HOST reads bit on rising edge.
313 CLOCK ~~~~~~~~~~~~|__|~~~|__|~~~|__|~~~|__|~~~|__|~~~|__|~~~|__|~~~|__|~~~~~~~~~~~
314 DATA ~~~~~~~~~~~~X777777X666666X555555X444444X333333X222222X111111X000000X~~~~~~~
315 <--> 160us(clock low)
316 <---> 180us(clock high)
317
318 3) HOST->KEYBOARD: HOST asserts bit on falling edge.
319 CLOCK ~~~~~~~~~~~~|__|~~~|__|~~~|__|~~~|__|~~~|__|~~~|__|~~~|__|~~~|__|~~~~~~~~~~~
320 DATA ~~~~~~|_____X777777X666666X555555X444444X333333X222222X111111X000000X~~~~~~~
321 <----> 840us(request to send by host) <---> 80us(hold DATA)
322 <--> 180us(clock low)
323 <---> 220us(clock high)
324
325
326 Protocol
327 --------
328 COMMAND:
329 Inquiry 0x10 get key event
330 Instant 0x12 get key event
331 Model 0x14 get model number(M0110 responds with 0x09)
332 bit 7 1 if another device connected(used when keypad exists?)
333 bit4-6 next device model number
334 bit1-3 keyboard model number
335 bit 0 always 1
336 Test 0x16 test(ACK:0x7D/NAK:0x77)
337
338 KEY EVENT:
339 bit 7 key state(0:press 1:release)
340 bit 6-1 scan code(see below)
341 bit 0 always 1
342 To get scan code use this: ((bits&(1<<7)) | ((bits&0x7F))>>1).
343
344 Note: On the M0110A, the numpad keys and the arrow keys are preceded by 0x79.
345 Moreover, the numpad keys =, /, * and + are preceded by shift-down 0x71 on press and shift-up 0xF1 on release.
346 So, the data transferred by nupmad 5 is "79 2F" whereas for numpad + it's "71 79 0D".
347
348 ARROW KEYS:
349 Arrow keys and Pad+,*,/,=(Calc keys) share same byte sequence and its preceding byte
350 0x71 and 0xF1 means press and release event of SHIFT. These cause very confusing situation.
351 It is difficult or impossible to tell Calc key from Arrow key with SHIFT in some cases.
352
353 Raw key events:
354 press release
355 ---------------- ----------------
356 Left: 0x79, 0x0D 0x79, 0x8D
357 Right: 0x79, 0x05 0x79, 0x85
358 Up: 0x79, 0x1B 0x79, 0x9B
359 Down: 0x79, 0x11 0x79, 0x91
360 Pad+: 0x71, 0x79, 0x0D 0xF1, 0x79, 0x8D
361 Pad*: 0x71, 0x79, 0x05 0xF1, 0x79, 0x85
362 Pad/: 0x71, 0x79, 0x1B 0xF1, 0x79, 0x9B
363 Pad=: 0x71, 0x79, 0x11 0xF1, 0x79, 0x91
364
365 SCAN CODE:
366 m0111_recv_key() function returns follwing scan codes instead of raw key events.
367 Scan codes are 1 byte long and bit7 is set when key is released.
368
369 M0110
370 ,---------------------------------------------------------.
371 | `| 1| 2| 3| 4| 5| 6| 7| 8| 9| 0| -| =|Backs|
372 |---------------------------------------------------------|
373 |Tab | Q| W| E| R| T| Y| U| I| O| P| [| ]| \|
374 |---------------------------------------------------------|
375 |CapsLo| A| S| D| F| G| H| J| K| L| ;| '|Return|
376 |---------------------------------------------------------|
377 |Shift | Z| X| C| V| B| N| M| ,| ,| /| |
378 `---------------------------------------------------------'
379 |Opt|Mac | Space |Enter|Opt|
380 `------------------------------------------------'
381 ,---------------------------------------------------------.
382 | 32| 12| 13| 14| 15| 17| 16| 1A| 1C| 19| 1D| 1B| 18| 33|
383 |---------------------------------------------------------|
384 | 30| 0C| 0D| 0E| 0F| 10| 11| 20| 22| 1F| 23| 21| 1E| 2A|
385 |---------------------------------------------------------|
386 | 39| 00| 01| 02| 03| 05| 04| 26| 28| 25| 29| 27| 24|
387 |---------------------------------------------------------|
388 | 38| 06| 07| 08| 09| 0B| 2D| 2E| 2B| 2F| 2C| 38|
389 `---------------------------------------------------------'
390 | 3A| 37| 31 | 34| 3A|
391 `------------------------------------------------'
392
393 M0110A
394 ,---------------------------------------------------------. ,---------------.
395 | `| 1| 2| 3| 4| 5| 6| 7| 8| 9| 0| -| =|Bcksp| |Clr| =| /| *|
396 |---------------------------------------------------------| |---------------|
397 |Tab | Q| W| E| R| T| Y| U| I| O| P| [| ]| | | 7| 8| 9| -|
398 |-----------------------------------------------------' | |---------------|
399 |CapsLo| A| S| D| F| G| H| J| K| L| ;| '|Return| | 4| 5| 6| +|
400 |---------------------------------------------------------| |---------------|
401 |Shift | Z| X| C| V| B| N| M| ,| ,| /|Shft|Up | | 1| 2| 3| |
402 |---------------------------------------------------------' |-----------|Ent|
403 |Optio|Mac | Space | \|Lft|Rgt|Dn | | 0| .| |
404 `---------------------------------------------------------' `---------------'
405 ,---------------------------------------------------------. ,---------------.
406 | 32| 12| 13| 14| 15| 17| 16| 1A| 1C| 19| 1D| 1B| 18| 33| | 47| 68| 6D| 62|
407 |---------------------------------------------------------| |---------------|
408 | 30| 0C| 0D| 0E| 0F| 10| 11| 20| 22| 1F| 23| 21| 1E| | | 59| 5B| 5C| 4E|
409 |-----------------------------------------------------' | |---------------|
410 | 39| 00| 01| 02| 03| 05| 04| 26| 28| 25| 29| 27| 24| | 56| 57| 58| 66|
411 |---------------------------------------------------------| |---------------|
412 | 38| 06| 07| 08| 09| 0B| 2D| 2E| 2B| 2F| 2C| 38| 4D| | 53| 54| 55| |
413 |---------------------------------------------------------' |-----------| 4C|
414 | 3A| 37| 31 | 2A| 46| 42| 48| | 52| 41| |
415 `---------------------------------------------------------' `---------------'
416
417
418 References
419 ----------
420 Technical Info for 128K/512K and Plus
421 ftp://ftp.apple.asimov.net/pub/apple_II/documentation/macintosh/Mac%20Hardware%20Info%20-%20Mac%20128K.pdf
422 ftp://ftp.apple.asimov.net/pub/apple_II/documentation/macintosh/Mac%20Hardware%20Info%20-%20Mac%20Plus.pdf
423 Protocol:
424 Page 20 of Tech Info for 128K/512K
425 http://www.mac.linux-m68k.org/devel/plushw.php
426 Connector:
427 Page 20 of Tech Info for 128K/512K
428 http://www.kbdbabel.org/conn/kbd_connector_macplus.png
429 Signaling:
430 http://www.kbdbabel.org/signaling/kbd_signaling_mac.png
431 http://typematic.blog.shinobi.jp/Entry/14/
432 Scan Codes:
433 Page 22 of Tech Info for 128K/512K
434 Page 07 of Tech Info for Plus
435 http://m0115.web.fc2.com/m0110.jpg
436 http://m0115.web.fc2.com/m0110a.jpg
437 */
Imprint / Impressum