]> git.gir.st - tmk_keyboard.git/blob - m0110.c
Workaround for Mac HID SET_IDLE behaviour.
[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 lines are 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(see below)
102 bit 0 always 1
103 To get scan code use this: ((bits&(1<<7)) | ((bits&0x7F))>>1).
104
105 Note: On the M0110A, the numpad keys and the arrow keys are preceded by 0x79.
106 Moreover, the numpad keys =, /, * and + are preceded by shift-down 0x71 on press and shift-up 0xF1 on release.
107 So, the data transferred by nupmad 5 is "79 2F" whereas for numpad + it's "71 79 0D".
108
109 SCAN CODE:
110 m0111_recv_key() function returns follwing scan codes instead of raw key events.
111 Scan codes are 1 byte long and bit7 is set when key is released.
112
113 M0110
114 ,---------------------------------------------------------.
115 | `| 1| 2| 3| 4| 5| 6| 7| 8| 9| 0| -| =|Backs|
116 |---------------------------------------------------------|
117 |Tab | Q| W| E| R| T| Y| U| I| O| P| [| ]| \|
118 |---------------------------------------------------------|
119 |CapsLo| A| S| D| F| G| H| J| K| L| ;| '|Return|
120 |---------------------------------------------------------|
121 |Shift | Z| X| C| V| B| N| M| ,| ,| /| |
122 `---------------------------------------------------------'
123 |Opt|Mac | Space |Enter|Opt|
124 `------------------------------------------------'
125 ,---------------------------------------------------------.
126 | 32| 12| 13| 14| 15| 17| 16| 1A| 1C| 19| 1D| 1B| 18| 33|
127 |---------------------------------------------------------|
128 | 30| 0C| 0D| 0E| 0F| 10| 11| 20| 22| 1F| 23| 21| 1E| 2A|
129 |---------------------------------------------------------|
130 | 39| 00| 01| 02| 03| 05| 04| 26| 28| 25| 29| 27| 24|
131 |---------------------------------------------------------|
132 | 38| 06| 07| 08| 09| 0B| 2D| 2E| 2B| 2F| 2C| 38|
133 `---------------------------------------------------------'
134 | 3A| 37| 31 | 34| 3A|
135 `------------------------------------------------'
136
137 M0110A
138 ,---------------------------------------------------------. ,---------------.
139 | `| 1| 2| 3| 4| 5| 6| 7| 8| 9| 0| -| =|Bcksp| |Clr| =| /| *|
140 |---------------------------------------------------------| |---------------|
141 |Tab | Q| W| E| R| T| Y| U| I| O| P| [| ]| | | 7| 8| 9| -|
142 |-----------------------------------------------------' | |---------------|
143 |CapsLo| A| S| D| F| G| H| J| K| L| ;| '|Return| | 4| 5| 6| +|
144 |---------------------------------------------------------| |---------------|
145 |Shift | Z| X| C| V| B| N| M| ,| ,| /|Shft|Up | | 1| 2| 3| |
146 |---------------------------------------------------------' |-----------|Ent|
147 |Optio|Mac | Space | \|Lft|Rgt|Dn | | 0| .| |
148 `---------------------------------------------------------' `---------------'
149 ,---------------------------------------------------------. ,---------------.
150 | 32| 12| 13| 14| 15| 17| 16| 1A| 1C| 19| 1D| 1B| 18| 33| | 47| 68| 6D| 62|
151 |---------------------------------------------------------| |---------------|
152 | 30| 0C| 0D| 0E| 0F| 10| 11| 20| 22| 1F| 23| 21| 1E| | | 59| 5B| 5C| 4E|
153 |-----------------------------------------------------' | |---------------|
154 | 39| 00| 01| 02| 03| 05| 04| 26| 28| 25| 29| 27| 24| | 56| 57| 58| 66|
155 |---------------------------------------------------------| |---------------|
156 | 38| 06| 07| 08| 09| 0B| 2D| 2E| 2B| 2F| 2C| 38| 4D| | 53| 54| 55| |
157 |---------------------------------------------------------' |-----------| 4C|
158 | 3A| 37| 31 | 2A| 46| 42| 48| | 52| 41| |
159 `---------------------------------------------------------' `---------------'
160
161
162 References
163 ----------
164 Technical Info for 128K/512K and Plus
165 ftp://ftp.apple.asimov.net/pub/apple_II/documentation/macintosh/Mac%20Hardware%20Info%20-%20Mac%20128K.pdf
166 ftp://ftp.apple.asimov.net/pub/apple_II/documentation/macintosh/Mac%20Hardware%20Info%20-%20Mac%20Plus.pdf
167 Protocol:
168 Page 20 of Tech Info for 128K/512K
169 http://www.mac.linux-m68k.org/devel/plushw.php
170 Connector:
171 Page 20 of Tech Info for 128K/512K
172 http://www.kbdbabel.org/conn/kbd_connector_macplus.png
173 Signaling:
174 http://www.kbdbabel.org/signaling/kbd_signaling_mac.png
175 http://typematic.blog.shinobi.jp/Entry/14/
176 Scan Codes:
177 Page 22 of Tech Info for 128K/512K
178 Page 07 of Tech Info for Plus
179 http://m0115.web.fc2.com/m0110.jpg
180 http://m0115.web.fc2.com/m0110a.jpg
181 */
182
183
184 #define WAIT_US(stat, us, err) do { \
185 if (!wait_##stat(us)) { \
186 m0110_error = err; \
187 goto ERROR; \
188 } \
189 } while (0)
190
191 #define WAIT_MS(stat, ms, err) do { \
192 uint16_t _ms = ms; \
193 while (_ms) { \
194 if (wait_##stat(1000)) { \
195 break; \
196 } \
197 _ms--; \
198 } \
199 if (_ms == 0) { \
200 m0110_error = err; \
201 goto ERROR; \
202 } \
203 } while (0)
204
205
206 uint8_t m0110_error = 0;
207
208
209 void m0110_init(void)
210 {
211 uint8_t data;
212 idle();
213 _delay_ms(1000);
214
215 // Model Number
216 // M0110 : 0x09 00001001 : model number 4 (100)
217 // M0110A: 0x0B 00001011 : model number 5 (101)
218 // M0110 & M0120: ???
219 m0110_send(M0110_MODEL);
220 data = m0110_recv();
221 print("m0110_init model: "); phex(data); print("\n");
222
223 m0110_send(M0110_TEST);
224 data = m0110_recv();
225 print("m0110_init test: "); phex(data); print("\n");
226 }
227
228 uint8_t m0110_send(uint8_t data)
229 {
230 m0110_error = 0;
231
232 request();
233 WAIT_MS(clock_lo, 250, 1); // keyboard may block long time
234 for (uint8_t bit = 0x80; bit; bit >>= 1) {
235 WAIT_US(clock_lo, 250, 3);
236 if (data&bit) {
237 data_hi();
238 } else {
239 data_lo();
240 }
241 WAIT_US(clock_hi, 200, 4);
242 }
243 _delay_us(100); // hold last bit for 80us
244 idle();
245 return 1;
246 ERROR:
247 print("m0110_send err: "); phex(m0110_error); print("\n");
248 _delay_ms(500);
249 idle();
250 return 0;
251 }
252
253 uint8_t m0110_recv(void)
254 {
255 uint8_t data = 0;
256 m0110_error = 0;
257
258 WAIT_MS(clock_lo, 250, 1); // keyboard may block long time
259 for (uint8_t i = 0; i < 8; i++) {
260 data <<= 1;
261 WAIT_US(clock_lo, 200, 2);
262 WAIT_US(clock_hi, 200, 3);
263 if (data_in()) {
264 data |= 1;
265 }
266 }
267 idle();
268 return data;
269 ERROR:
270 print("m0110_recv err: "); phex(m0110_error); print("\n");
271 _delay_ms(500);
272 idle();
273 return 0xFF;
274 }
275
276 uint8_t m0110_recv_key(void)
277 {
278 uint8_t key;
279 m0110_send(M0110_INQUIRY);
280 key = m0110_recv();
281 if (key == 0xFF || key == M0110_NULL)
282 return M0110_NULL;
283 else
284 return M0110_RAW2SCAN(key);
285 }
286
287
288 static inline void clock_lo()
289 {
290 M0110_CLOCK_PORT &= ~(1<<M0110_CLOCK_BIT);
291 M0110_CLOCK_DDR |= (1<<M0110_CLOCK_BIT);
292 }
293 static inline void clock_hi()
294 {
295 /* input with pull up */
296 M0110_CLOCK_DDR &= ~(1<<M0110_CLOCK_BIT);
297 M0110_CLOCK_PORT |= (1<<M0110_CLOCK_BIT);
298 }
299 static inline bool clock_in()
300 {
301 M0110_CLOCK_DDR &= ~(1<<M0110_CLOCK_BIT);
302 M0110_CLOCK_PORT |= (1<<M0110_CLOCK_BIT);
303 _delay_us(1);
304 return M0110_CLOCK_PIN&(1<<M0110_CLOCK_BIT);
305 }
306 static inline void data_lo()
307 {
308 M0110_DATA_PORT &= ~(1<<M0110_DATA_BIT);
309 M0110_DATA_DDR |= (1<<M0110_DATA_BIT);
310 }
311 static inline void data_hi()
312 {
313 /* input with pull up */
314 M0110_DATA_DDR &= ~(1<<M0110_DATA_BIT);
315 M0110_DATA_PORT |= (1<<M0110_DATA_BIT);
316 }
317 static inline bool data_in()
318 {
319 M0110_DATA_DDR &= ~(1<<M0110_DATA_BIT);
320 M0110_DATA_PORT |= (1<<M0110_DATA_BIT);
321 _delay_us(1);
322 return M0110_DATA_PIN&(1<<M0110_DATA_BIT);
323 }
324
325 static inline uint16_t wait_clock_lo(uint16_t us)
326 {
327 while (clock_in() && us) { asm(""); _delay_us(1); us--; }
328 return us;
329 }
330 static inline uint16_t wait_clock_hi(uint16_t us)
331 {
332 while (!clock_in() && us) { asm(""); _delay_us(1); us--; }
333 return us;
334 }
335 static inline uint16_t wait_data_lo(uint16_t us)
336 {
337 while (data_in() && us) { asm(""); _delay_us(1); us--; }
338 return us;
339 }
340 static inline uint16_t wait_data_hi(uint16_t us)
341 {
342 while (!data_in() && us) { asm(""); _delay_us(1); us--; }
343 return us;
344 }
345
346 static inline void idle(void)
347 {
348 clock_hi();
349 data_hi();
350 }
351
352 static inline void request(void)
353 {
354 clock_hi();
355 data_lo();
356 }
Imprint / Impressum