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 | */ |