]> git.donarmstrong.com Git - qmk_firmware.git/blob - m0110.c
added SONY NEWS keyboard NWP-5461 support.
[qmk_firmware.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     M0110
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     if (data != M0110_NULL) {
215         print("m0110_recv data: "); phex(data); print("\n");
216     }
217     return data;
218 ERROR:
219     if (m0110_error) {
220         print("m0110_recv err: "); phex(m0110_error); print("\n");
221     }
222     idle();
223     return 0xFF;
224 }
225
226 uint8_t m0110_recv_key(void)
227 {
228     uint8_t key;
229     m0110_send(M0110_INQUIRY);
230     key = m0110_recv();
231     if (key == 0xFF || key == M0110_NULL)
232         return M0110_NULL;
233     else 
234         return ((key&(1<<7)) | ((key&0x7F)>>1));
235 }
236
237
238 static inline void clock_lo()
239 {
240     M0110_CLOCK_PORT &= ~(1<<M0110_CLOCK_BIT);
241     M0110_CLOCK_DDR  |=  (1<<M0110_CLOCK_BIT);
242 }
243 static inline void clock_hi()
244 {
245     /* input with pull up */
246     M0110_CLOCK_DDR  &= ~(1<<M0110_CLOCK_BIT);
247     M0110_CLOCK_PORT |=  (1<<M0110_CLOCK_BIT);
248 }
249 static inline bool clock_in()
250 {
251     M0110_CLOCK_DDR  &= ~(1<<M0110_CLOCK_BIT);
252     M0110_CLOCK_PORT |=  (1<<M0110_CLOCK_BIT);
253     _delay_us(1);
254     return M0110_CLOCK_PIN&(1<<M0110_CLOCK_BIT);
255 }
256 static inline void data_lo()
257 {
258     M0110_DATA_PORT &= ~(1<<M0110_DATA_BIT);
259     M0110_DATA_DDR  |=  (1<<M0110_DATA_BIT);
260 }
261 static inline void data_hi()
262 {
263     /* input with pull up */
264     M0110_DATA_DDR  &= ~(1<<M0110_DATA_BIT);
265     M0110_DATA_PORT |=  (1<<M0110_DATA_BIT);
266 }
267 static inline bool data_in()
268 {
269     M0110_DATA_DDR  &= ~(1<<M0110_DATA_BIT);
270     M0110_DATA_PORT |=  (1<<M0110_DATA_BIT);
271     _delay_us(1);
272     return M0110_DATA_PIN&(1<<M0110_DATA_BIT);
273 }
274
275 static inline uint16_t wait_clock_lo(uint16_t us)
276 {
277     while (clock_in()  && us) { asm(""); _delay_us(1); us--; }
278     return us;
279 }
280 static inline uint16_t wait_clock_hi(uint16_t us)
281 {
282     while (!clock_in() && us) { asm(""); _delay_us(1); us--; }
283     return us;
284 }
285 static inline uint16_t wait_data_lo(uint16_t us)
286 {
287     while (data_in() && us)  { asm(""); _delay_us(1); us--; }
288     return us;
289 }
290 static inline uint16_t wait_data_hi(uint16_t us)
291 {
292     while (!data_in() && us)  { asm(""); _delay_us(1); us--; }
293     return us;
294 }
295
296 static inline void idle(void)
297 {
298     clock_hi();
299     data_hi();
300 }
301
302 static inline void request(void)
303 {
304     clock_hi();
305     data_lo();
306 }