diff options
| -rw-r--r-- | converter/adb_usb/led.c | 5 | ||||
| -rw-r--r-- | converter/adb_usb/matrix.c | 7 | ||||
| -rw-r--r-- | protocol/adb.c | 208 |
3 files changed, 108 insertions, 112 deletions
diff --git a/converter/adb_usb/led.c b/converter/adb_usb/led.c index 0e162f379..1e7911f94 100644 --- a/converter/adb_usb/led.c +++ b/converter/adb_usb/led.c | |||
| @@ -15,12 +15,15 @@ You should have received a copy of the GNU General Public License | |||
| 15 | along with this program. If not, see <http://www.gnu.org/licenses/>. | 15 | along with this program. If not, see <http://www.gnu.org/licenses/>. |
| 16 | */ | 16 | */ |
| 17 | 17 | ||
| 18 | #include "stdint.h" | 18 | #include <stdint.h> |
| 19 | #include <util/delay.h> | ||
| 19 | #include "adb.h" | 20 | #include "adb.h" |
| 20 | #include "led.h" | 21 | #include "led.h" |
| 21 | 22 | ||
| 22 | 23 | ||
| 23 | void led_set(uint8_t usb_led) | 24 | void led_set(uint8_t usb_led) |
| 24 | { | 25 | { |
| 26 | // need a wait to send command without miss | ||
| 27 | _delay_ms(100); | ||
| 25 | adb_host_kbd_led(~usb_led); | 28 | adb_host_kbd_led(~usb_led); |
| 26 | } | 29 | } |
diff --git a/converter/adb_usb/matrix.c b/converter/adb_usb/matrix.c index 7e5856971..54be2b0f5 100644 --- a/converter/adb_usb/matrix.c +++ b/converter/adb_usb/matrix.c | |||
| @@ -67,6 +67,13 @@ uint8_t matrix_cols(void) | |||
| 67 | void matrix_init(void) | 67 | void matrix_init(void) |
| 68 | { | 68 | { |
| 69 | adb_host_init(); | 69 | adb_host_init(); |
| 70 | // wait for keyboard to boot up and receive command | ||
| 71 | _delay_ms(1000); | ||
| 72 | // Enable keyboard left/right modifier distinction | ||
| 73 | // Addr:Keyboard(0010), Cmd:Listen(10), Register3(11) | ||
| 74 | // upper byte: reserved bits 0000, device address 0010 | ||
| 75 | // lower byte: device handler 00000011 | ||
| 76 | adb_host_listen(0x2B,0x02,0x03); | ||
| 70 | 77 | ||
| 71 | // initialize matrix state: all keys off | 78 | // initialize matrix state: all keys off |
| 72 | for (uint8_t i=0; i < MATRIX_ROWS; i++) matrix[i] = 0x00; | 79 | for (uint8_t i=0; i < MATRIX_ROWS; i++) matrix[i] = 0x00; |
diff --git a/protocol/adb.c b/protocol/adb.c index f706255ad..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, |
| @@ -43,9 +44,11 @@ POSSIBILITY OF SUCH DAMAGE. | |||
| 43 | #include "debug.h" | 44 | #include "debug.h" |
| 44 | 45 | ||
| 45 | 46 | ||
| 46 | static inline void data_lo(void); | 47 | // GCC doesn't inline functions normally |
| 47 | static inline void data_hi(void); | 48 | #define data_lo() (ADB_DDR |= (1<<ADB_DATA_BIT)) |
| 48 | 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 | |||
| 49 | #ifdef ADB_PSW_BIT | 52 | #ifdef ADB_PSW_BIT |
| 50 | static inline void psw_lo(void); | 53 | static inline void psw_lo(void); |
| 51 | static inline void psw_hi(void); | 54 | static inline void psw_hi(void); |
| @@ -56,24 +59,17 @@ static inline void attention(void); | |||
| 56 | static inline void place_bit0(void); | 59 | static inline void place_bit0(void); |
| 57 | static inline void place_bit1(void); | 60 | static inline void place_bit1(void); |
| 58 | static inline void send_byte(uint8_t data); | 61 | static inline void send_byte(uint8_t data); |
| 59 | static inline bool read_bit(void); | 62 | static inline uint16_t wait_data_lo(uint16_t us); |
| 60 | static inline uint8_t read_byte(void); | 63 | static inline uint16_t wait_data_hi(uint16_t us); |
| 61 | static inline uint8_t wait_data_lo(uint16_t us); | ||
| 62 | static inline uint8_t wait_data_hi(uint8_t us); | ||
| 63 | 64 | ||
| 64 | 65 | ||
| 65 | void adb_host_init(void) | 66 | void adb_host_init(void) |
| 66 | { | 67 | { |
| 68 | ADB_PORT &= ~(1<<ADB_DATA_BIT); | ||
| 67 | data_hi(); | 69 | data_hi(); |
| 68 | #ifdef ADB_PSW_BIT | 70 | #ifdef ADB_PSW_BIT |
| 69 | psw_hi(); | 71 | psw_hi(); |
| 70 | #endif | 72 | #endif |
| 71 | |||
| 72 | // Enable keyboard left/right modifier distinction | ||
| 73 | // Addr:Keyboard(0010), Cmd:Listen(10), Register3(11) | ||
| 74 | // upper byte: reserved bits 0000, device address 0010 | ||
| 75 | // lower byte: device handler 00000011 | ||
| 76 | adb_host_listen(0x2B,0x02,0x03); | ||
| 77 | } | 73 | } |
| 78 | 74 | ||
| 79 | #ifdef ADB_PSW_BIT | 75 | #ifdef ADB_PSW_BIT |
| @@ -91,6 +87,41 @@ bool adb_host_psw(void) | |||
| 91 | * <http://geekhack.org/index.php?topic=14290.msg1068919#msg1068919> | 87 | * <http://geekhack.org/index.php?topic=14290.msg1068919#msg1068919> |
| 92 | * <http://geekhack.org/index.php?topic=14290.msg1070139#msg1070139> | 88 | * <http://geekhack.org/index.php?topic=14290.msg1070139#msg1070139> |
| 93 | */ | 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 | |||
| 94 | uint16_t adb_host_kbd_recv(void) | 125 | uint16_t adb_host_kbd_recv(void) |
| 95 | { | 126 | { |
| 96 | uint16_t data = 0; | 127 | uint16_t data = 0; |
| @@ -100,24 +131,50 @@ uint16_t adb_host_kbd_recv(void) | |||
| 100 | if (!wait_data_lo(500)) { // Tlt/Stop to Start(140-260us) | 131 | if (!wait_data_lo(500)) { // Tlt/Stop to Start(140-260us) |
| 101 | return 0; // No data to send | 132 | return 0; // No data to send |
| 102 | } | 133 | } |
| 103 | if (!read_bit()) { // Startbit(1) | 134 | |
| 104 | // Service Request | ||
| 105 | dprintf("Startbit ERROR\n"); | ||
| 106 | return -2; | ||
| 107 | } | ||
| 108 | |||
| 109 | // 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 |
| 110 | cli(); | 136 | // TODO: is this needed anymore with improved timing? |
| 111 | data = read_byte(); | 137 | //cli(); |
| 112 | data = (data<<8) | read_byte(); | 138 | uint8_t n = 17; // start bit + 16 data bits |
| 113 | uint8_t stop = read_bit(); // Stopbit(0) | 139 | do { |
| 114 | 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 ); | ||
| 115 | 163 | ||
| 116 | 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)) { | ||
| 117 | dprintf("Stopbit ERROR\n"); | 167 | dprintf("Stopbit ERROR\n"); |
| 168 | sei(); | ||
| 118 | return -3; | 169 | return -3; |
| 119 | } | 170 | } |
| 171 | sei(); | ||
| 120 | return data; | 172 | return data; |
| 173 | |||
| 174 | error: | ||
| 175 | dprintf("Bit ERROR\n"); | ||
| 176 | sei(); | ||
| 177 | return -4; | ||
| 121 | } | 178 | } |
| 122 | 179 | ||
| 123 | 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) |
| @@ -142,23 +199,6 @@ void adb_host_kbd_led(uint8_t led) | |||
| 142 | } | 199 | } |
| 143 | 200 | ||
| 144 | 201 | ||
| 145 | static inline void data_lo() | ||
| 146 | { | ||
| 147 | ADB_DDR |= (1<<ADB_DATA_BIT); | ||
| 148 | ADB_PORT &= ~(1<<ADB_DATA_BIT); | ||
| 149 | } | ||
| 150 | static inline void data_hi() | ||
| 151 | { | ||
| 152 | ADB_PORT |= (1<<ADB_DATA_BIT); | ||
| 153 | ADB_DDR &= ~(1<<ADB_DATA_BIT); | ||
| 154 | } | ||
| 155 | static inline bool data_in() | ||
| 156 | { | ||
| 157 | ADB_PORT |= (1<<ADB_DATA_BIT); | ||
| 158 | ADB_DDR &= ~(1<<ADB_DATA_BIT); | ||
| 159 | return ADB_PIN&(1<<ADB_DATA_BIT); | ||
| 160 | } | ||
| 161 | |||
| 162 | #ifdef ADB_PSW_BIT | 202 | #ifdef ADB_PSW_BIT |
| 163 | static inline void psw_lo() | 203 | static inline void psw_lo() |
| 164 | { | 204 | { |
| @@ -181,7 +221,7 @@ static inline bool psw_in() | |||
| 181 | static inline void attention(void) | 221 | static inline void attention(void) |
| 182 | { | 222 | { |
| 183 | data_lo(); | 223 | data_lo(); |
| 184 | _delay_us(700); | 224 | _delay_us(800-35); // bit1 holds lo for 35 more |
| 185 | place_bit1(); | 225 | place_bit1(); |
| 186 | } | 226 | } |
| 187 | 227 | ||
| @@ -211,81 +251,27 @@ static inline void send_byte(uint8_t data) | |||
| 211 | } | 251 | } |
| 212 | } | 252 | } |
| 213 | 253 | ||
| 214 | static inline bool read_bit(void) | 254 | // These are carefully coded to take 6 cycles of overhead. |
| 215 | { | 255 | // inline asm approach became too convoluted |
| 216 | // ADB Bit Cells | 256 | static inline uint16_t wait_data_lo(uint16_t us) |
| 217 | // | ||
| 218 | // bit cell time: 70-130us | ||
| 219 | // low part of bit0: 60-70% of bit cell | ||
| 220 | // low part of bit1: 30-40% of bit cell | ||
| 221 | // | ||
| 222 | // bit cell time 70us 130us | ||
| 223 | // -------------------------------------------- | ||
| 224 | // low part of bit0 42-49 78-91 | ||
| 225 | // high part of bit0 21-28 39-52 | ||
| 226 | // low part of bit1 21-28 39-52 | ||
| 227 | // high part of bit1 42-49 78-91 | ||
| 228 | // | ||
| 229 | // | ||
| 230 | // bit0: | ||
| 231 | // 70us bit cell: | ||
| 232 | // ____________~~~~~~ | ||
| 233 | // 42-49 21-28 | ||
| 234 | // | ||
| 235 | // 130us bit cell: | ||
| 236 | // ____________~~~~~~ | ||
| 237 | // 78-91 39-52 | ||
| 238 | // | ||
| 239 | // bit1: | ||
| 240 | // 70us bit cell: | ||
| 241 | // ______~~~~~~~~~~~~ | ||
| 242 | // 21-28 42-49 | ||
| 243 | // | ||
| 244 | // 130us bit cell: | ||
| 245 | // ______~~~~~~~~~~~~ | ||
| 246 | // 39-52 78-91 | ||
| 247 | // | ||
| 248 | // read: | ||
| 249 | // ________|~~~~~~~~~ | ||
| 250 | // 55us | ||
| 251 | // Read data line after 55us. If data line is low/high then bit is 0/1. | ||
| 252 | // This method might not work at <90us bit cell time. | ||
| 253 | // | ||
| 254 | // [from Apple IIgs Hardware Reference Second Edition] | ||
| 255 | bool bit; | ||
| 256 | wait_data_lo(75); // wait the start of bit cell at least 130ms(55+0+75) | ||
| 257 | _delay_us(55); | ||
| 258 | bit = data_in(); | ||
| 259 | wait_data_hi(36); // wait high part of bit cell at least 91ms(55+36) | ||
| 260 | return bit; | ||
| 261 | } | ||
| 262 | |||
| 263 | static inline uint8_t read_byte(void) | ||
| 264 | { | ||
| 265 | uint8_t data = 0; | ||
| 266 | for (int i = 0; i < 8; i++) { | ||
| 267 | data <<= 1; | ||
| 268 | if (read_bit()) | ||
| 269 | data = data | 1; | ||
| 270 | } | ||
| 271 | return data; | ||
| 272 | } | ||
| 273 | |||
| 274 | static inline uint8_t wait_data_lo(uint16_t us) | ||
| 275 | { | 257 | { |
| 276 | while (data_in() && us) { | 258 | do { |
| 277 | _delay_us(1); | 259 | if ( !data_in() ) |
| 278 | us--; | 260 | break; |
| 261 | _delay_us(1 - (6 * 1000000.0 / F_CPU)); | ||
| 279 | } | 262 | } |
| 263 | while ( --us ); | ||
| 280 | return us; | 264 | return us; |
| 281 | } | 265 | } |
| 282 | 266 | ||
| 283 | static inline uint8_t wait_data_hi(uint8_t us) | 267 | static inline uint16_t wait_data_hi(uint16_t us) |
| 284 | { | 268 | { |
| 285 | while (!data_in() && us) { | 269 | do { |
| 286 | _delay_us(1); | 270 | if ( data_in() ) |
| 287 | us--; | 271 | break; |
| 272 | _delay_us(1 - (6 * 1000000.0 / F_CPU)); | ||
| 288 | } | 273 | } |
| 274 | while ( --us ); | ||
| 289 | return us; | 275 | return us; |
| 290 | } | 276 | } |
| 291 | 277 | ||
