SHOW:
|
|
- or go back to the newest paste.
1 | /* | |
2 | Copyright 2011 Jun WAKO <[email protected]> | |
3 | Copyright 2013 Shay Green <[email protected]> | |
4 | ||
5 | This software is licensed with a Modified BSD License. | |
6 | All of this is supposed to be Free Software, Open Source, DFSG-free, | |
7 | GPL-compatible, and OK to use in both free and proprietary applications. | |
8 | Additions and corrections to this file are welcome. | |
9 | ||
10 | ||
11 | Redistribution and use in source and binary forms, with or without | |
12 | modification, are permitted provided that the following conditions are met: | |
13 | ||
14 | * Redistributions of source code must retain the above copyright | |
15 | notice, this list of conditions and the following disclaimer. | |
16 | ||
17 | * Redistributions in binary form must reproduce the above copyright | |
18 | notice, this list of conditions and the following disclaimer in | |
19 | the documentation and/or other materials provided with the | |
20 | distribution. | |
21 | ||
22 | * Neither the name of the copyright holders nor the names of | |
23 | contributors may be used to endorse or promote products derived | |
24 | from this software without specific prior written permission. | |
25 | ||
26 | THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" | |
27 | AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE | |
28 | IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE | |
29 | ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE | |
30 | LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR | |
31 | CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF | |
32 | SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS | |
33 | INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN | |
34 | CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) | |
35 | ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE | |
36 | POSSIBILITY OF SUCH DAMAGE. | |
37 | */ | |
38 | ||
39 | #include <stdbool.h> | |
40 | #include <util/delay.h> | |
41 | #include <avr/io.h> | |
42 | #include <avr/interrupt.h> | |
43 | #include "adb.h" | |
44 | #include "debug.h" | |
45 | ||
46 | ||
47 | // GCC doesn't inline functions normally | |
48 | #define data_lo() (ADB_DDR |= (1<<ADB_DATA_BIT)) | |
49 | #define data_hi() (ADB_DDR &= ~(1<<ADB_DATA_BIT)) | |
50 | #define data_in() (ADB_PIN & (1<<ADB_DATA_BIT)) | |
51 | ||
52 | #ifdef ADB_PSW_BIT | |
53 | static inline void psw_lo(void); | |
54 | static inline void psw_hi(void); | |
55 | static inline bool psw_in(void); | |
56 | #endif | |
57 | ||
58 | static inline void attention(void); | |
59 | static inline void place_bit0(void); | |
60 | static inline void place_bit1(void); | |
61 | static inline void send_byte(uint8_t data); | |
62 | static inline uint16_t wait_data_lo(uint16_t us); | |
63 | static inline uint16_t wait_data_hi(uint16_t us); | |
64 | ||
65 | ||
66 | void adb_host_init(void) | |
67 | { | |
68 | ADB_PORT &= ~(1<<ADB_DATA_BIT); | |
69 | data_hi(); | |
70 | #ifdef ADB_PSW_BIT | |
71 | psw_hi(); | |
72 | #endif | |
73 | ||
74 | // Enable keyboard left/right modifier distinction | |
75 | // Addr:Keyboard(0010), Cmd:Listen(10), Register3(11) | |
76 | // upper byte: reserved bits 0000, device address 0010 | |
77 | // lower byte: device handler 00000011 | |
78 | adb_host_listen(0x2B,0x02,0x03); | |
79 | } | |
80 | ||
81 | #ifdef ADB_PSW_BIT | |
82 | bool adb_host_psw(void) | |
83 | { | |
84 | return psw_in(); | |
85 | } | |
86 | #endif | |
87 | ||
88 | /* | |
89 | * Don't call this in a row without the delay, otherwise it makes some of poor controllers | |
90 | * overloaded and misses strokes. Recommended interval is 12ms. | |
91 | * | |
92 | * Thanks a lot, blargg! | |
93 | * <http://geekhack.org/index.php?topic=14290.msg1068919#msg1068919> | |
94 | * <http://geekhack.org/index.php?topic=14290.msg1070139#msg1070139> | |
95 | */ | |
96 | ||
97 | // ADB Bit Cells | |
98 | // | |
99 | // bit cell time: 70-130us | |
100 | // low part of bit0: 60-70% of bit cell | |
101 | // low part of bit1: 30-40% of bit cell | |
102 | // | |
103 | // bit cell time 70us 130us | |
104 | // -------------------------------------------- | |
105 | // low part of bit0 42-49 78-91 | |
106 | // high part of bit0 21-28 39-52 | |
107 | // low part of bit1 21-28 39-52 | |
108 | // high part of bit1 42-49 78-91 | |
109 | // | |
110 | // | |
111 | // bit0: | |
112 | // 70us bit cell: | |
113 | // ____________~~~~~~ | |
114 | // 42-49 21-28 | |
115 | // | |
116 | // 130us bit cell: | |
117 | // ____________~~~~~~ | |
118 | // 78-91 39-52 | |
119 | // | |
120 | // bit1: | |
121 | // 70us bit cell: | |
122 | // ______~~~~~~~~~~~~ | |
123 | // 21-28 42-49 | |
124 | // | |
125 | // 130us bit cell: | |
126 | // ______~~~~~~~~~~~~ | |
127 | // 39-52 78-91 | |
128 | // | |
129 | // [from Apple IIgs Hardware Reference Second Edition] | |
130 | ||
131 | uint16_t adb_host_kbd_recv(void) | |
132 | { | |
133 | uint16_t data = 0; | |
134 | attention(); | |
135 | send_byte(0x2C); // Addr:Keyboard(0010), Cmd:Talk(11), Register0(00) | |
136 | place_bit0(); // Stopbit(0) | |
137 | if (!wait_data_lo(500)) { // Tlt/Stop to Start(140-260us) | |
138 | return 0; // No data to send | |
139 | } | |
140 | ||
141 | // ad hoc fix: without block inerrupt read wrong bit occasionally and get keys stuck | |
142 | // TODO: is this needed anymore with improved timing? | |
143 | //cli(); | |
144 | uint8_t n = 17; // start bit + 16 data bits | |
145 | do { | |
146 | uint8_t lo = (uint8_t) wait_data_hi(130); | |
147 | if (!lo) | |
148 | goto error; | |
149 | ||
150 | uint8_t hi = (uint8_t) wait_data_lo(lo); | |
151 | if (!hi) | |
152 | goto error; | |
153 | ||
154 | hi = lo - hi; | |
155 | lo = 130 - lo; | |
156 | ||
157 | data <<= 1; | |
158 | if (lo < hi) { | |
159 | data |= 1; | |
160 | } | |
161 | else if (n == 17) { | |
162 | // Service Request | |
163 | dprintf("Startbit ERROR\n"); | |
164 | sei(); | |
165 | return -2; | |
166 | } | |
167 | } | |
168 | while ( --n ); | |
169 | ||
170 | // Stop bit can't be checked normally since it could have service request lenghtening | |
171 | // and its high state never goes low. | |
172 | if (!wait_data_hi(351) || wait_data_lo(91)) { | |
173 | dprintf("Stopbit ERROR\n"); | |
174 | sei(); | |
175 | return -3; | |
176 | } | |
177 | sei(); | |
178 | return data; | |
179 | ||
180 | error: | |
181 | dprintf("Bit ERROR\n"); | |
182 | sei(); | |
183 | return -4; | |
184 | } | |
185 | ||
186 | void adb_host_listen(uint8_t cmd, uint8_t data_h, uint8_t data_l) | |
187 | { | |
188 | attention(); | |
189 | send_byte(cmd); | |
190 | place_bit0(); // Stopbit(0) | |
191 | _delay_us(200); // Tlt/Stop to Start | |
192 | place_bit1(); // Startbit(1) | |
193 | send_byte(data_h); | |
194 | send_byte(data_l); | |
195 | place_bit0(); // Stopbit(0); | |
196 | } | |
197 | ||
198 | // send state of LEDs | |
199 | void adb_host_kbd_led(uint8_t led) | |
200 | { | |
201 | // Addr:Keyboard(0010), Cmd:Listen(10), Register2(10) | |
202 | // send upper byte (not used) | |
203 | // send lower byte (bit2: ScrollLock, bit1: CapsLock, bit0: | |
204 | adb_host_listen(0x2A,0,led&0x07); | |
205 | } | |
206 | ||
207 | ||
208 | #ifdef ADB_PSW_BIT | |
209 | static inline void psw_lo() | |
210 | { | |
211 | ADB_DDR |= (1<<ADB_PSW_BIT); | |
212 | ADB_PORT &= ~(1<<ADB_PSW_BIT); | |
213 | } | |
214 | static inline void psw_hi() | |
215 | { | |
216 | ADB_PORT |= (1<<ADB_PSW_BIT); | |
217 | ADB_DDR &= ~(1<<ADB_PSW_BIT); | |
218 | } | |
219 | static inline bool psw_in() | |
220 | { | |
221 | ADB_PORT |= (1<<ADB_PSW_BIT); | |
222 | ADB_DDR &= ~(1<<ADB_PSW_BIT); | |
223 | return ADB_PIN&(1<<ADB_PSW_BIT); | |
224 | } | |
225 | #endif | |
226 | ||
227 | static inline void attention(void) | |
228 | { | |
229 | data_lo(); | |
230 | _delay_us(800-35); // bit1 holds lo for 35 more | |
231 | place_bit1(); | |
232 | } | |
233 | ||
234 | static inline void place_bit0(void) | |
235 | { | |
236 | data_lo(); | |
237 | _delay_us(65); | |
238 | data_hi(); | |
239 | _delay_us(35); | |
240 | } | |
241 | ||
242 | static inline void place_bit1(void) | |
243 | { | |
244 | data_lo(); | |
245 | _delay_us(35); | |
246 | data_hi(); | |
247 | _delay_us(65); | |
248 | } | |
249 | ||
250 | static inline void send_byte(uint8_t data) | |
251 | { | |
252 | for (int i = 0; i < 8; i++) { | |
253 | if (data&(0x80>>i)) | |
254 | place_bit1(); | |
255 | else | |
256 | place_bit0(); | |
257 | } | |
258 | } | |
259 | ||
260 | // These are carefully coded to take 6 cycles of overhead. | |
261 | // inline asm approach became too convoluted | |
262 | static inline uint16_t wait_data_lo(uint16_t us) | |
263 | { | |
264 | do { | |
265 | if ( !data_in() ) | |
266 | break; | |
267 | _delay_us(1 - (6 * 1000000.0 / F_CPU)); | |
268 | } | |
269 | while ( --us ); | |
270 | return us; | |
271 | } | |
272 | ||
273 | static inline uint16_t wait_data_hi(uint16_t us) | |
274 | { | |
275 | do { | |
276 | if ( data_in() ) | |
277 | break; | |
278 | _delay_us(1 - (6 * 1000000.0 / F_CPU)); | |
279 | } | |
280 | while ( --us ); | |
281 | return us; | |
282 | } | |
283 | ||
284 | ||
285 | /* | |
286 | ADB Protocol | |
287 | ============ | |
288 | ||
289 | Resources | |
290 | --------- | |
291 | ADB - The Untold Story: Space Aliens Ate My Mouse | |
292 | http://developer.apple.com/legacy/mac/library/#technotes/hw/hw_01.html | |
293 | ADB Manager | |
294 | http://developer.apple.com/legacy/mac/library/documentation/mac/pdf/Devices/ADB_Manager.pdf | |
295 | Service request(5-17) | |
296 | Apple IIgs Hardware Reference Second Edition [Chapter6 p121] | |
297 | ftp://ftp.apple.asimov.net/pub/apple_II/documentation/Apple%20IIgs%20Hardware%20Reference.pdf | |
298 | ADB Keycode | |
299 | http://72.0.193.250/Documentation/macppc/adbkeycodes/ | |
300 | http://m0115.web.fc2.com/m0115.jpg | |
301 | [Inside Macintosh volume V, pages 191-192] | |
302 | http://www.opensource.apple.com/source/IOHIDFamily/IOHIDFamily-421.18.3/IOHIDFamily/Cosmo_USB2ADB.c | |
303 | ADB Signaling | |
304 | http://kbdbabel.sourceforge.net/doc/kbd_signaling_pcxt_ps2_adb.pdf | |
305 | ADB Overview & History | |
306 | http://en.wikipedia.org/wiki/Apple_Desktop_Bus | |
307 | Microchip Application Note: ADB device(with code for PIC16C) | |
308 | http://www.microchip.com/stellent/idcplg?IdcService=SS_GET_PAGE&nodeId=1824&appnote=en011062 | |
309 | AVR ATtiny2131 ADB to PS/2 converter(Japanese) | |
310 | http://hp.vector.co.jp/authors/VA000177/html/KeyBoardA5DEA5CBA5A2II.html | |
311 | ||
312 | ||
313 | Pinouts | |
314 | ------- | |
315 | ADB female socket from the front: | |
316 | __________ | |
317 | | | <--- top | |
318 | | 4o o3 | | |
319 | |2o o1| | |
320 | | == | | |
321 | |________| <--- bottom | |
322 | | | <--- 4pins | |
323 | ||
324 | ||
325 | ADB female socket from bottom: | |
326 | ||
327 | ========== <--- front | |
328 | | | | |
329 | | | | |
330 | |2o o1| | |
331 | |4o o3| | |
332 | ---------- <--- back | |
333 | ||
334 | 1: Data | |
335 | 2: Power SW(low when press Power key) | |
336 | 3: Vcc(5V) | |
337 | 4: GND | |
338 | ||
339 | ||
340 | Commands | |
341 | -------- | |
342 | ADB command is 1byte and consists of 4bit-address, 2bit-command | |
343 | type and 2bit-register. The commands are always sent by Host. | |
344 | ||
345 | Command format: | |
346 | 7 6 5 4 3 2 1 0 | |
347 | | | | |------------ address | |
348 | | |-------- command type | |
349 | | |---- register | |
350 | ||
351 | bits commands | |
352 | ------------------------------------------------------ | |
353 | - - - - 0 0 0 0 Send Request(reset all devices) | |
354 | A A A A 0 0 0 1 Flush(reset a device) | |
355 | - - - - 0 0 1 0 Reserved | |
356 | - - - - 0 0 1 1 Reserved | |
357 | - - - - 0 1 - - Reserved | |
358 | A A A A 1 0 R R Listen(write to a device) | |
359 | A A A A 1 1 R R Talk(read from a device) | |
360 | ||
361 | The command to read keycodes from keyboard is 0x2C which | |
362 | consist of keyboard address 2 and Talk against register 0. | |
363 | ||
364 | Address: | |
365 | 2: keyboard | |
366 | 3: mice | |
367 | ||
368 | Registers: | |
369 | 0: application(keyobard uses this to store its data.) | |
370 | 1: application | |
371 | 2: application(keyboard uses this for LEDs and state of modifiers) | |
372 | 3: status and command | |
373 | ||
374 | ||
375 | Communication | |
376 | ------------- | |
377 | This is a minimum information for keyboard communication. | |
378 | See "Resources" for detail. | |
379 | ||
380 | Signaling: | |
381 | ||
382 | ~~~~____________~~||||||||||||__~~~~~_~~|||||||||||||||__~~~~ | |
383 | ||
384 | |800us | |7 Command 0| | | |15-64 Data 0|Stopbit(0) | |
385 | +Attention | | | +Startbit(1) | |
386 | +Startbit(1) | +Tlt(140-260us) | |
387 | +stopbit(0) | |
388 | ||
389 | Bit cells: | |
390 | ||
391 | bit0: ______~~~ | |
392 | 65 :35us | |
393 | ||
394 | bit1: ___~~~~~~ | |
395 | 35 :65us | |
396 | ||
397 | bit0 low time: 60-70% of bit cell(42-91us) | |
398 | bit1 low time: 30-40% of bit cell(21-52us) | |
399 | bit cell time: 70-130us | |
400 | [from Apple IIgs Hardware Reference Second Edition] | |
401 | ||
402 | Criterion for bit0/1: | |
403 | After 55us if line is low/high then bit is 0/1. | |
404 | ||
405 | Attention & start bit: | |
406 | Host asserts low in 560-1040us then places start bit(1). | |
407 | ||
408 | Tlt(Stop to Start): | |
409 | Bus stays high in 140-260us then device places start bit(1). | |
410 | ||
411 | Global reset: | |
412 | Host asserts low in 2.8-5.2ms. All devices are forced to reset. | |
413 | ||
414 | Service request from device(Srq): | |
415 | Device can request to send at commad(Global only?) stop bit. | |
416 | Requesting device keeps low for 140-260us at stop bit of command. | |
417 | ||
418 | ||
419 | Keyboard Data(Register0) | |
420 | This 16bit data can contains two keycodes and two released flags. | |
421 | First keycode is palced in upper byte. When one keyocode is sent, | |
422 | lower byte is 0xFF. | |
423 | Release flag is 1 when key is released. | |
424 | ||
425 | 1514 . . . . . 8 7 6 . . . . . 0 | |
426 | | | | | | | | | | +-+-+-+-+-+-+- Keycode2 | |
427 | | | | | | | | | +--------------- Released2(1 when the key is released) | |
428 | | +-+-+-+-+-+-+----------------- Keycode1 | |
429 | +------------------------------- Released1(1 when the key is released) | |
430 | ||
431 | Keycodes: | |
432 | Scancode consists of 7bit keycode and 1bit release flag. | |
433 | Device can send two keycodes at once. If just one keycode is sent | |
434 | keycode1 contains it and keyocode2 is 0xFF. | |
435 | ||
436 | Power switch: | |
437 | You can read the state from PSW line(active low) however | |
438 | the switch has a special scancode 0x7F7F, so you can | |
439 | also read from Data line. It uses 0xFFFF for release scancode. | |
440 | ||
441 | Keyboard LEDs & state of keys(Register2) | |
442 | This register hold current state of three LEDs and nine keys. | |
443 | The state of LEDs can be changed by sending Listen command. | |
444 | ||
445 | 1514 . . . . . . 7 6 5 . 3 2 1 0 | |
446 | | | | | | | | | | | | | | | | +- LED1(NumLock) | |
447 | | | | | | | | | | | | | | | +--- LED2(CapsLock) | |
448 | | | | | | | | | | | | | | +----- LED3(ScrollLock) | |
449 | | | | | | | | | | | +-+-+------- Reserved | |
450 | | | | | | | | | | +------------- ScrollLock | |
451 | | | | | | | | | +--------------- NumLock | |
452 | | | | | | | | +----------------- Apple/Command | |
453 | | | | | | | +------------------- Option | |
454 | | | | | | +--------------------- Shift | |
455 | | | | | +----------------------- Control | |
456 | | | | +------------------------- Reset/Power | |
457 | | | +--------------------------- CapsLock | |
458 | | +----------------------------- Delete | |
459 | +------------------------------- Reserved | |
460 | ||
461 | END_OF_ADB | |
462 | */ |