diff options
Diffstat (limited to 'protocol/adb.c')
| -rw-r--r-- | protocol/adb.c | 217 |
1 files changed, 107 insertions, 110 deletions
diff --git a/protocol/adb.c b/protocol/adb.c index 2baad3234..750f4b965 100644 --- a/protocol/adb.c +++ b/protocol/adb.c | |||
| @@ -1,5 +1,6 @@ | |||
| 1 | /* | 1 | /* |
| 2 | Copyright 2011 Jun WAKO <wakojun@gmail.com> | 2 | Copyright 2011 Jun WAKO <wakojun@gmail.com> |
| 3 | Copyright 2013 Shay Green <gblargg@gmail.com> | ||
| 3 | 4 | ||
| 4 | This software is licensed with a Modified BSD License. | 5 | This software is licensed with a Modified BSD License. |
| 5 | All of this is supposed to be Free Software, Open Source, DFSG-free, | 6 | All of this is supposed to be Free Software, Open Source, DFSG-free, |
| @@ -40,11 +41,14 @@ POSSIBILITY OF SUCH DAMAGE. | |||
| 40 | #include <avr/io.h> | 41 | #include <avr/io.h> |
| 41 | #include <avr/interrupt.h> | 42 | #include <avr/interrupt.h> |
| 42 | #include "adb.h" | 43 | #include "adb.h" |
| 44 | #include "debug.h" | ||
| 43 | 45 | ||
| 44 | 46 | ||
| 45 | static inline void data_lo(void); | 47 | // GCC doesn't inline functions normally |
| 46 | static inline void data_hi(void); | 48 | #define data_lo() (ADB_DDR |= (1<<ADB_DATA_BIT)) |
| 47 | static inline bool data_in(void); | 49 | #define data_hi() (ADB_DDR &= ~(1<<ADB_DATA_BIT)) |
| 50 | #define data_in() (ADB_PIN & (1<<ADB_DATA_BIT)) | ||
| 51 | |||
| 48 | #ifdef ADB_PSW_BIT | 52 | #ifdef ADB_PSW_BIT |
| 49 | static inline void psw_lo(void); | 53 | static inline void psw_lo(void); |
| 50 | static inline void psw_hi(void); | 54 | static inline void psw_hi(void); |
| @@ -55,24 +59,17 @@ static inline void attention(void); | |||
| 55 | static inline void place_bit0(void); | 59 | static inline void place_bit0(void); |
| 56 | static inline void place_bit1(void); | 60 | static inline void place_bit1(void); |
| 57 | static inline void send_byte(uint8_t data); | 61 | static inline void send_byte(uint8_t data); |
| 58 | static inline bool read_bit(void); | 62 | static inline uint16_t wait_data_lo(uint16_t us); |
| 59 | static inline uint8_t read_byte(void); | 63 | static inline uint16_t wait_data_hi(uint16_t us); |
| 60 | static inline uint8_t wait_data_lo(uint16_t us); | ||
| 61 | static inline uint8_t wait_data_hi(uint8_t us); | ||
| 62 | 64 | ||
| 63 | 65 | ||
| 64 | void adb_host_init(void) | 66 | void adb_host_init(void) |
| 65 | { | 67 | { |
| 68 | ADB_PORT &= ~(1<<ADB_DATA_BIT); | ||
| 66 | data_hi(); | 69 | data_hi(); |
| 67 | #ifdef ADB_PSW_BIT | 70 | #ifdef ADB_PSW_BIT |
| 68 | psw_hi(); | 71 | psw_hi(); |
| 69 | #endif | 72 | #endif |
| 70 | |||
| 71 | // Enable keyboard left/right modifier distinction | ||
| 72 | // Addr:Keyboard(0010), Cmd:Listen(10), Register3(11) | ||
| 73 | // upper byte: reserved bits 0000, device address 0010 | ||
| 74 | // lower byte: device handler 00000011 | ||
| 75 | adb_host_listen(0x2B,0x02,0x03); | ||
| 76 | } | 73 | } |
| 77 | 74 | ||
| 78 | #ifdef ADB_PSW_BIT | 75 | #ifdef ADB_PSW_BIT |
| @@ -82,6 +79,49 @@ bool adb_host_psw(void) | |||
| 82 | } | 79 | } |
| 83 | #endif | 80 | #endif |
| 84 | 81 | ||
| 82 | /* | ||
| 83 | * Don't call this in a row without the delay, otherwise it makes some of poor controllers | ||
| 84 | * overloaded and misses strokes. Recommended interval is 12ms. | ||
| 85 | * | ||
| 86 | * Thanks a lot, blargg! | ||
| 87 | * <http://geekhack.org/index.php?topic=14290.msg1068919#msg1068919> | ||
| 88 | * <http://geekhack.org/index.php?topic=14290.msg1070139#msg1070139> | ||
| 89 | */ | ||
| 90 | |||
| 91 | // ADB Bit Cells | ||
| 92 | // | ||
| 93 | // bit cell time: 70-130us | ||
| 94 | // low part of bit0: 60-70% of bit cell | ||
| 95 | // low part of bit1: 30-40% of bit cell | ||
| 96 | // | ||
| 97 | // bit cell time 70us 130us | ||
| 98 | // -------------------------------------------- | ||
| 99 | // low part of bit0 42-49 78-91 | ||
| 100 | // high part of bit0 21-28 39-52 | ||
| 101 | // low part of bit1 21-28 39-52 | ||
| 102 | // high part of bit1 42-49 78-91 | ||
| 103 | // | ||
| 104 | // | ||
| 105 | // bit0: | ||
| 106 | // 70us bit cell: | ||
| 107 | // ____________~~~~~~ | ||
| 108 | // 42-49 21-28 | ||
| 109 | // | ||
| 110 | // 130us bit cell: | ||
| 111 | // ____________~~~~~~ | ||
| 112 | // 78-91 39-52 | ||
| 113 | // | ||
| 114 | // bit1: | ||
| 115 | // 70us bit cell: | ||
| 116 | // ______~~~~~~~~~~~~ | ||
| 117 | // 21-28 42-49 | ||
| 118 | // | ||
| 119 | // 130us bit cell: | ||
| 120 | // ______~~~~~~~~~~~~ | ||
| 121 | // 39-52 78-91 | ||
| 122 | // | ||
| 123 | // [from Apple IIgs Hardware Reference Second Edition] | ||
| 124 | |||
| 85 | uint16_t adb_host_kbd_recv(void) | 125 | uint16_t adb_host_kbd_recv(void) |
| 86 | { | 126 | { |
| 87 | uint16_t data = 0; | 127 | uint16_t data = 0; |
| @@ -91,22 +131,50 @@ uint16_t adb_host_kbd_recv(void) | |||
| 91 | if (!wait_data_lo(500)) { // Tlt/Stop to Start(140-260us) | 131 | if (!wait_data_lo(500)) { // Tlt/Stop to Start(140-260us) |
| 92 | return 0; // No data to send | 132 | return 0; // No data to send |
| 93 | } | 133 | } |
| 94 | if (!read_bit()) { // Startbit(1) | 134 | |
| 95 | // Service Request | ||
| 96 | return -2; | ||
| 97 | } | ||
| 98 | |||
| 99 | // ad hoc fix: without block inerrupt read wrong bit occasionally and get keys stuck | 135 | // ad hoc fix: without block inerrupt read wrong bit occasionally and get keys stuck |
| 100 | cli(); | 136 | // TODO: is this needed anymore with improved timing? |
| 101 | data = read_byte(); | 137 | //cli(); |
| 102 | data = (data<<8) | read_byte(); | 138 | uint8_t n = 17; // start bit + 16 data bits |
| 103 | uint8_t stop = read_bit(); // Stopbit(0) | 139 | do { |
| 104 | sei(); | 140 | uint8_t lo = (uint8_t) wait_data_hi(130); |
| 141 | if (!lo) | ||
| 142 | goto error; | ||
| 143 | |||
| 144 | uint8_t hi = (uint8_t) wait_data_lo(lo); | ||
| 145 | if (!hi) | ||
| 146 | goto error; | ||
| 147 | |||
| 148 | hi = lo - hi; | ||
| 149 | lo = 130 - lo; | ||
| 150 | |||
| 151 | data <<= 1; | ||
| 152 | if (lo < hi) { | ||
| 153 | data |= 1; | ||
| 154 | } | ||
| 155 | else if (n == 17) { | ||
| 156 | // Service Request | ||
| 157 | dprintf("Startbit ERROR\n"); | ||
| 158 | sei(); | ||
| 159 | return -2; | ||
| 160 | } | ||
| 161 | } | ||
| 162 | while ( --n ); | ||
| 105 | 163 | ||
| 106 | if (stop) { | 164 | // Stop bit can't be checked normally since it could have service request lenghtening |
| 165 | // and its high state never goes low. | ||
| 166 | if (!wait_data_hi(351) || wait_data_lo(91)) { | ||
| 167 | dprintf("Stopbit ERROR\n"); | ||
| 168 | sei(); | ||
| 107 | return -3; | 169 | return -3; |
| 108 | } | 170 | } |
| 171 | sei(); | ||
| 109 | return data; | 172 | return data; |
| 173 | |||
| 174 | error: | ||
| 175 | dprintf("Bit ERROR\n"); | ||
| 176 | sei(); | ||
| 177 | return -4; | ||
| 110 | } | 178 | } |
| 111 | 179 | ||
| 112 | void adb_host_listen(uint8_t cmd, uint8_t data_h, uint8_t data_l) | 180 | void adb_host_listen(uint8_t cmd, uint8_t data_h, uint8_t data_l) |
| @@ -131,23 +199,6 @@ void adb_host_kbd_led(uint8_t led) | |||
| 131 | } | 199 | } |
| 132 | 200 | ||
| 133 | 201 | ||
| 134 | static inline void data_lo() | ||
| 135 | { | ||
| 136 | ADB_DDR |= (1<<ADB_DATA_BIT); | ||
| 137 | ADB_PORT &= ~(1<<ADB_DATA_BIT); | ||
| 138 | } | ||
| 139 | static inline void data_hi() | ||
| 140 | { | ||
| 141 | ADB_PORT |= (1<<ADB_DATA_BIT); | ||
| 142 | ADB_DDR &= ~(1<<ADB_DATA_BIT); | ||
| 143 | } | ||
| 144 | static inline bool data_in() | ||
| 145 | { | ||
| 146 | ADB_PORT |= (1<<ADB_DATA_BIT); | ||
| 147 | ADB_DDR &= ~(1<<ADB_DATA_BIT); | ||
| 148 | return ADB_PIN&(1<<ADB_DATA_BIT); | ||
| 149 | } | ||
| 150 | |||
| 151 | #ifdef ADB_PSW_BIT | 202 | #ifdef ADB_PSW_BIT |
| 152 | static inline void psw_lo() | 203 | static inline void psw_lo() |
| 153 | { | 204 | { |
| @@ -170,7 +221,7 @@ static inline bool psw_in() | |||
| 170 | static inline void attention(void) | 221 | static inline void attention(void) |
| 171 | { | 222 | { |
| 172 | data_lo(); | 223 | data_lo(); |
| 173 | _delay_us(700); | 224 | _delay_us(800-35); // bit1 holds lo for 35 more |
| 174 | place_bit1(); | 225 | place_bit1(); |
| 175 | } | 226 | } |
| 176 | 227 | ||
| @@ -200,81 +251,27 @@ static inline void send_byte(uint8_t data) | |||
| 200 | } | 251 | } |
| 201 | } | 252 | } |
| 202 | 253 | ||
| 203 | static inline bool read_bit(void) | 254 | // These are carefully coded to take 6 cycles of overhead. |
| 204 | { | 255 | // inline asm approach became too convoluted |
| 205 | // ADB Bit Cells | 256 | static inline uint16_t wait_data_lo(uint16_t us) |
| 206 | // | ||
| 207 | // bit cell time: 70-130us | ||
| 208 | // low part of bit0: 60-70% of bit cell | ||
| 209 | // low part of bit1: 30-40% of bit cell | ||
| 210 | // | ||
| 211 | // bit cell time 70us 130us | ||
| 212 | // -------------------------------------------- | ||
| 213 | // low part of bit0 42-49 78-91 | ||
| 214 | // high part of bit0 21-28 39-52 | ||
| 215 | // low part of bit1 21-28 39-52 | ||
| 216 | // high part of bit1 42-49 78-91 | ||
| 217 | // | ||
| 218 | // | ||
| 219 | // bit0: | ||
| 220 | // 70us bit cell: | ||
| 221 | // ____________~~~~~~ | ||
| 222 | // 42-49 21-28 | ||
| 223 | // | ||
| 224 | // 130us bit cell: | ||
| 225 | // ____________~~~~~~ | ||
| 226 | // 78-91 39-52 | ||
| 227 | // | ||
| 228 | // bit1: | ||
| 229 | // 70us bit cell: | ||
| 230 | // ______~~~~~~~~~~~~ | ||
| 231 | // 21-28 42-49 | ||
| 232 | // | ||
| 233 | // 130us bit cell: | ||
| 234 | // ______~~~~~~~~~~~~ | ||
| 235 | // 39-52 78-91 | ||
| 236 | // | ||
| 237 | // read: | ||
| 238 | // ________|~~~~~~~~~ | ||
| 239 | // 55us | ||
| 240 | // Read data line after 55us. If data line is low/high then bit is 0/1. | ||
| 241 | // This method might not work at <90us bit cell time. | ||
| 242 | // | ||
| 243 | // [from Apple IIgs Hardware Reference Second Edition] | ||
| 244 | bool bit; | ||
| 245 | wait_data_lo(75); // wait the start of bit cell at least 130ms(55+0+75) | ||
| 246 | _delay_us(55); | ||
| 247 | bit = data_in(); | ||
| 248 | wait_data_hi(36); // wait high part of bit cell at least 91ms(55+36) | ||
| 249 | return bit; | ||
| 250 | } | ||
| 251 | |||
| 252 | static inline uint8_t read_byte(void) | ||
| 253 | { | ||
| 254 | uint8_t data = 0; | ||
| 255 | for (int i = 0; i < 8; i++) { | ||
| 256 | data <<= 1; | ||
| 257 | if (read_bit()) | ||
| 258 | data = data | 1; | ||
| 259 | } | ||
| 260 | return data; | ||
| 261 | } | ||
| 262 | |||
| 263 | static inline uint8_t wait_data_lo(uint16_t us) | ||
| 264 | { | 257 | { |
| 265 | while (data_in() && us) { | 258 | do { |
| 266 | _delay_us(1); | 259 | if ( !data_in() ) |
| 267 | us--; | 260 | break; |
| 261 | _delay_us(1 - (6 * 1000000.0 / F_CPU)); | ||
| 268 | } | 262 | } |
| 263 | while ( --us ); | ||
| 269 | return us; | 264 | return us; |
| 270 | } | 265 | } |
| 271 | 266 | ||
| 272 | static inline uint8_t wait_data_hi(uint8_t us) | 267 | static inline uint16_t wait_data_hi(uint16_t us) |
| 273 | { | 268 | { |
| 274 | while (!data_in() && us) { | 269 | do { |
| 275 | _delay_us(1); | 270 | if ( data_in() ) |
| 276 | us--; | 271 | break; |
| 272 | _delay_us(1 - (6 * 1000000.0 / F_CPU)); | ||
| 277 | } | 273 | } |
| 274 | while ( --us ); | ||
| 278 | return us; | 275 | return us; |
| 279 | } | 276 | } |
| 280 | 277 | ||
