2 Copyright 2011 Jun WAKO <wakojun@gmail.com>
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.
10 Redistribution and use in source and binary forms, with or without
11 modification, are permitted provided that the following conditions are met:
13 * Redistributions of source code must retain the above copyright
14 notice, this list of conditions and the following disclaimer.
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
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.
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.
40 #include <avr/interrupt.h>
41 #include <util/delay.h>
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);
61 Primitive M0110 Library for AVR
62 ==============================
67 CLOCK is always from KEYBOARD. DATA are sent with MSB first.
69 1) IDLE: both lines are high.
70 CLOCK ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
71 DATA ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
73 2) KEYBOARD->HOST: HOST reads bit on rising edge.
74 CLOCK ~~~~~~~~~~~~|__|~~~|__|~~~|__|~~~|__|~~~|__|~~~|__|~~~|__|~~~|__|~~~~~~~~~~~
75 DATA ~~~~~~~~~~~~X777777X666666X555555X444444X333333X222222X111111X000000X~~~~~~~
77 <---> 180us(clock high)
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)
84 <---> 220us(clock high)
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
97 Test 0x16 test(ACK:0x7D/NAK:0x77)
100 bit 7 key state(0:press 1:release)
101 bit 6-1 scan code(see below)
103 To get scan code use this: ((bits&(1<<7)) | ((bits&0x7F))>>1).
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".
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.
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 `------------------------------------------------'
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 `---------------------------------------------------------' `---------------'
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
168 Page 20 of Tech Info for 128K/512K
169 http://www.mac.linux-m68k.org/devel/plushw.php
171 Page 20 of Tech Info for 128K/512K
172 http://www.kbdbabel.org/conn/kbd_connector_macplus.png
174 http://www.kbdbabel.org/signaling/kbd_signaling_mac.png
175 http://typematic.blog.shinobi.jp/Entry/14/
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
184 #define WAIT_US(stat, us, err) do { \
185 if (!wait_##stat(us)) { \
191 #define WAIT_MS(stat, ms, err) do { \
194 if (wait_##stat(1000)) { \
206 uint8_t m0110_error = 0;
209 void m0110_init(void)
216 // M0110 : 0x09 00001001 : model number 4 (100)
217 // M0110A: 0x0B 00001011 : model number 5 (101)
218 // M0110 & M0120: ???
219 m0110_send(M0110_MODEL);
221 print("m0110_init model: "); phex(data); print("\n");
223 m0110_send(M0110_TEST);
225 print("m0110_init test: "); phex(data); print("\n");
228 uint8_t m0110_send(uint8_t data)
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);
241 WAIT_US(clock_hi, 200, 4);
243 _delay_us(100); // hold last bit for 80us
247 print("m0110_send err: "); phex(m0110_error); print("\n");
253 uint8_t m0110_recv(void)
258 WAIT_MS(clock_lo, 250, 1); // keyboard may block long time
259 for (uint8_t i = 0; i < 8; i++) {
261 WAIT_US(clock_lo, 200, 2);
262 WAIT_US(clock_hi, 200, 3);
270 print("m0110_recv err: "); phex(m0110_error); print("\n");
276 uint8_t m0110_recv_key(void)
279 m0110_send(M0110_INQUIRY);
281 if (key == 0xFF || key == M0110_NULL)
284 return M0110_RAW2SCAN(key);
288 static inline void clock_lo()
290 M0110_CLOCK_PORT &= ~(1<<M0110_CLOCK_BIT);
291 M0110_CLOCK_DDR |= (1<<M0110_CLOCK_BIT);
293 static inline void clock_hi()
295 /* input with pull up */
296 M0110_CLOCK_DDR &= ~(1<<M0110_CLOCK_BIT);
297 M0110_CLOCK_PORT |= (1<<M0110_CLOCK_BIT);
299 static inline bool clock_in()
301 M0110_CLOCK_DDR &= ~(1<<M0110_CLOCK_BIT);
302 M0110_CLOCK_PORT |= (1<<M0110_CLOCK_BIT);
304 return M0110_CLOCK_PIN&(1<<M0110_CLOCK_BIT);
306 static inline void data_lo()
308 M0110_DATA_PORT &= ~(1<<M0110_DATA_BIT);
309 M0110_DATA_DDR |= (1<<M0110_DATA_BIT);
311 static inline void data_hi()
313 /* input with pull up */
314 M0110_DATA_DDR &= ~(1<<M0110_DATA_BIT);
315 M0110_DATA_PORT |= (1<<M0110_DATA_BIT);
317 static inline bool data_in()
319 M0110_DATA_DDR &= ~(1<<M0110_DATA_BIT);
320 M0110_DATA_PORT |= (1<<M0110_DATA_BIT);
322 return M0110_DATA_PIN&(1<<M0110_DATA_BIT);
325 static inline uint16_t wait_clock_lo(uint16_t us)
327 while (clock_in() && us) { asm(""); _delay_us(1); us--; }
330 static inline uint16_t wait_clock_hi(uint16_t us)
332 while (!clock_in() && us) { asm(""); _delay_us(1); us--; }
335 static inline uint16_t wait_data_lo(uint16_t us)
337 while (data_in() && us) { asm(""); _delay_us(1); us--; }
340 static inline uint16_t wait_data_hi(uint16_t us)
342 while (!data_in() && us) { asm(""); _delay_us(1); us--; }
346 static inline void idle(void)
352 static inline void request(void)