aboutsummaryrefslogtreecommitdiff
path: root/protocol/adb.c
diff options
context:
space:
mode:
Diffstat (limited to 'protocol/adb.c')
-rw-r--r--protocol/adb.c217
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/*
2Copyright 2011 Jun WAKO <wakojun@gmail.com> 2Copyright 2011 Jun WAKO <wakojun@gmail.com>
3Copyright 2013 Shay Green <gblargg@gmail.com>
3 4
4This software is licensed with a Modified BSD License. 5This software is licensed with a Modified BSD License.
5All of this is supposed to be Free Software, Open Source, DFSG-free, 6All 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
45static inline void data_lo(void); 47// GCC doesn't inline functions normally
46static inline void data_hi(void); 48#define data_lo() (ADB_DDR |= (1<<ADB_DATA_BIT))
47static 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
49static inline void psw_lo(void); 53static inline void psw_lo(void);
50static inline void psw_hi(void); 54static inline void psw_hi(void);
@@ -55,24 +59,17 @@ static inline void attention(void);
55static inline void place_bit0(void); 59static inline void place_bit0(void);
56static inline void place_bit1(void); 60static inline void place_bit1(void);
57static inline void send_byte(uint8_t data); 61static inline void send_byte(uint8_t data);
58static inline bool read_bit(void); 62static inline uint16_t wait_data_lo(uint16_t us);
59static inline uint8_t read_byte(void); 63static inline uint16_t wait_data_hi(uint16_t us);
60static inline uint8_t wait_data_lo(uint16_t us);
61static inline uint8_t wait_data_hi(uint8_t us);
62 64
63 65
64void adb_host_init(void) 66void 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
85uint16_t adb_host_kbd_recv(void) 125uint16_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
174error:
175 dprintf("Bit ERROR\n");
176 sei();
177 return -4;
110} 178}
111 179
112void adb_host_listen(uint8_t cmd, uint8_t data_h, uint8_t data_l) 180void 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
134static inline void data_lo()
135{
136 ADB_DDR |= (1<<ADB_DATA_BIT);
137 ADB_PORT &= ~(1<<ADB_DATA_BIT);
138}
139static inline void data_hi()
140{
141 ADB_PORT |= (1<<ADB_DATA_BIT);
142 ADB_DDR &= ~(1<<ADB_DATA_BIT);
143}
144static 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
152static inline void psw_lo() 203static inline void psw_lo()
153{ 204{
@@ -170,7 +221,7 @@ static inline bool psw_in()
170static inline void attention(void) 221static 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
203static 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 256static 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
252static 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
263static 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
272static inline uint8_t wait_data_hi(uint8_t us) 267static 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