Merge blargg's fix into adb.c
- <http://geekhack.org/index.php?topic=14290.msg1075201#msg1075201>
This commit is contained in:
parent
59ecced486
commit
c18c52f551
@ -15,12 +15,15 @@ You should have received a copy of the GNU General Public License
|
|||||||
along with this program. If not, see <http://www.gnu.org/licenses/>.
|
along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
#include "stdint.h"
|
#include <stdint.h>
|
||||||
|
#include <util/delay.h>
|
||||||
#include "adb.h"
|
#include "adb.h"
|
||||||
#include "led.h"
|
#include "led.h"
|
||||||
|
|
||||||
|
|
||||||
void led_set(uint8_t usb_led)
|
void led_set(uint8_t usb_led)
|
||||||
{
|
{
|
||||||
|
// need a wait to send command without miss
|
||||||
|
_delay_ms(100);
|
||||||
adb_host_kbd_led(~usb_led);
|
adb_host_kbd_led(~usb_led);
|
||||||
}
|
}
|
||||||
|
@ -67,6 +67,13 @@ uint8_t matrix_cols(void)
|
|||||||
void matrix_init(void)
|
void matrix_init(void)
|
||||||
{
|
{
|
||||||
adb_host_init();
|
adb_host_init();
|
||||||
|
// wait for keyboard to boot up and receive command
|
||||||
|
_delay_ms(1000);
|
||||||
|
// Enable keyboard left/right modifier distinction
|
||||||
|
// Addr:Keyboard(0010), Cmd:Listen(10), Register3(11)
|
||||||
|
// upper byte: reserved bits 0000, device address 0010
|
||||||
|
// lower byte: device handler 00000011
|
||||||
|
adb_host_listen(0x2B,0x02,0x03);
|
||||||
|
|
||||||
// initialize matrix state: all keys off
|
// initialize matrix state: all keys off
|
||||||
for (uint8_t i=0; i < MATRIX_ROWS; i++) matrix[i] = 0x00;
|
for (uint8_t i=0; i < MATRIX_ROWS; i++) matrix[i] = 0x00;
|
||||||
|
306
protocol/adb.c
306
protocol/adb.c
@ -1,5 +1,6 @@
|
|||||||
/*
|
/*
|
||||||
Copyright 2011 Jun WAKO <wakojun@gmail.com>
|
Copyright 2011 Jun WAKO <wakojun@gmail.com>
|
||||||
|
Copyright 2013 Shay Green <gblargg@gmail.com>
|
||||||
|
|
||||||
This software is licensed with a Modified BSD License.
|
This software is licensed with a Modified BSD License.
|
||||||
All of this is supposed to be Free Software, Open Source, DFSG-free,
|
All of this is supposed to be Free Software, Open Source, DFSG-free,
|
||||||
@ -43,9 +44,11 @@ POSSIBILITY OF SUCH DAMAGE.
|
|||||||
#include "debug.h"
|
#include "debug.h"
|
||||||
|
|
||||||
|
|
||||||
static inline void data_lo(void);
|
// GCC doesn't inline functions normally
|
||||||
static inline void data_hi(void);
|
#define data_lo() (ADB_DDR |= (1<<ADB_DATA_BIT))
|
||||||
static inline bool data_in(void);
|
#define data_hi() (ADB_DDR &= ~(1<<ADB_DATA_BIT))
|
||||||
|
#define data_in() (ADB_PIN & (1<<ADB_DATA_BIT))
|
||||||
|
|
||||||
#ifdef ADB_PSW_BIT
|
#ifdef ADB_PSW_BIT
|
||||||
static inline void psw_lo(void);
|
static inline void psw_lo(void);
|
||||||
static inline void psw_hi(void);
|
static inline void psw_hi(void);
|
||||||
@ -56,24 +59,17 @@ static inline void attention(void);
|
|||||||
static inline void place_bit0(void);
|
static inline void place_bit0(void);
|
||||||
static inline void place_bit1(void);
|
static inline void place_bit1(void);
|
||||||
static inline void send_byte(uint8_t data);
|
static inline void send_byte(uint8_t data);
|
||||||
static inline bool read_bit(void);
|
static inline uint16_t wait_data_lo(uint16_t us);
|
||||||
static inline uint8_t read_byte(void);
|
static inline uint16_t wait_data_hi(uint16_t us);
|
||||||
static inline uint8_t wait_data_lo(uint16_t us);
|
|
||||||
static inline uint8_t wait_data_hi(uint8_t us);
|
|
||||||
|
|
||||||
|
|
||||||
void adb_host_init(void)
|
void adb_host_init(void)
|
||||||
{
|
{
|
||||||
|
ADB_PORT &= ~(1<<ADB_DATA_BIT);
|
||||||
data_hi();
|
data_hi();
|
||||||
#ifdef ADB_PSW_BIT
|
#ifdef ADB_PSW_BIT
|
||||||
psw_hi();
|
psw_hi();
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
// Enable keyboard left/right modifier distinction
|
|
||||||
// Addr:Keyboard(0010), Cmd:Listen(10), Register3(11)
|
|
||||||
// upper byte: reserved bits 0000, device address 0010
|
|
||||||
// lower byte: device handler 00000011
|
|
||||||
adb_host_listen(0x2B,0x02,0x03);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
#ifdef ADB_PSW_BIT
|
#ifdef ADB_PSW_BIT
|
||||||
@ -91,128 +87,7 @@ bool adb_host_psw(void)
|
|||||||
* <http://geekhack.org/index.php?topic=14290.msg1068919#msg1068919>
|
* <http://geekhack.org/index.php?topic=14290.msg1068919#msg1068919>
|
||||||
* <http://geekhack.org/index.php?topic=14290.msg1070139#msg1070139>
|
* <http://geekhack.org/index.php?topic=14290.msg1070139#msg1070139>
|
||||||
*/
|
*/
|
||||||
uint16_t adb_host_kbd_recv(void)
|
|
||||||
{
|
|
||||||
uint16_t data = 0;
|
|
||||||
attention();
|
|
||||||
send_byte(0x2C); // Addr:Keyboard(0010), Cmd:Talk(11), Register0(00)
|
|
||||||
place_bit0(); // Stopbit(0)
|
|
||||||
if (!wait_data_lo(500)) { // Tlt/Stop to Start(140-260us)
|
|
||||||
return 0; // No data to send
|
|
||||||
}
|
|
||||||
if (!read_bit()) { // Startbit(1)
|
|
||||||
// Service Request
|
|
||||||
dprintf("Startbit ERROR\n");
|
|
||||||
return -2;
|
|
||||||
}
|
|
||||||
|
|
||||||
// ad hoc fix: without block inerrupt read wrong bit occasionally and get keys stuck
|
|
||||||
cli();
|
|
||||||
data = read_byte();
|
|
||||||
data = (data<<8) | read_byte();
|
|
||||||
uint8_t stop = read_bit(); // Stopbit(0)
|
|
||||||
sei();
|
|
||||||
|
|
||||||
if (stop) {
|
|
||||||
dprintf("Stopbit ERROR\n");
|
|
||||||
return -3;
|
|
||||||
}
|
|
||||||
return data;
|
|
||||||
}
|
|
||||||
|
|
||||||
void adb_host_listen(uint8_t cmd, uint8_t data_h, uint8_t data_l)
|
|
||||||
{
|
|
||||||
attention();
|
|
||||||
send_byte(cmd);
|
|
||||||
place_bit0(); // Stopbit(0)
|
|
||||||
_delay_us(200); // Tlt/Stop to Start
|
|
||||||
place_bit1(); // Startbit(1)
|
|
||||||
send_byte(data_h);
|
|
||||||
send_byte(data_l);
|
|
||||||
place_bit0(); // Stopbit(0);
|
|
||||||
}
|
|
||||||
|
|
||||||
// send state of LEDs
|
|
||||||
void adb_host_kbd_led(uint8_t led)
|
|
||||||
{
|
|
||||||
// Addr:Keyboard(0010), Cmd:Listen(10), Register2(10)
|
|
||||||
// send upper byte (not used)
|
|
||||||
// send lower byte (bit2: ScrollLock, bit1: CapsLock, bit0:
|
|
||||||
adb_host_listen(0x2A,0,led&0x07);
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
static inline void data_lo()
|
|
||||||
{
|
|
||||||
ADB_DDR |= (1<<ADB_DATA_BIT);
|
|
||||||
ADB_PORT &= ~(1<<ADB_DATA_BIT);
|
|
||||||
}
|
|
||||||
static inline void data_hi()
|
|
||||||
{
|
|
||||||
ADB_PORT |= (1<<ADB_DATA_BIT);
|
|
||||||
ADB_DDR &= ~(1<<ADB_DATA_BIT);
|
|
||||||
}
|
|
||||||
static inline bool data_in()
|
|
||||||
{
|
|
||||||
ADB_PORT |= (1<<ADB_DATA_BIT);
|
|
||||||
ADB_DDR &= ~(1<<ADB_DATA_BIT);
|
|
||||||
return ADB_PIN&(1<<ADB_DATA_BIT);
|
|
||||||
}
|
|
||||||
|
|
||||||
#ifdef ADB_PSW_BIT
|
|
||||||
static inline void psw_lo()
|
|
||||||
{
|
|
||||||
ADB_DDR |= (1<<ADB_PSW_BIT);
|
|
||||||
ADB_PORT &= ~(1<<ADB_PSW_BIT);
|
|
||||||
}
|
|
||||||
static inline void psw_hi()
|
|
||||||
{
|
|
||||||
ADB_PORT |= (1<<ADB_PSW_BIT);
|
|
||||||
ADB_DDR &= ~(1<<ADB_PSW_BIT);
|
|
||||||
}
|
|
||||||
static inline bool psw_in()
|
|
||||||
{
|
|
||||||
ADB_PORT |= (1<<ADB_PSW_BIT);
|
|
||||||
ADB_DDR &= ~(1<<ADB_PSW_BIT);
|
|
||||||
return ADB_PIN&(1<<ADB_PSW_BIT);
|
|
||||||
}
|
|
||||||
#endif
|
|
||||||
|
|
||||||
static inline void attention(void)
|
|
||||||
{
|
|
||||||
data_lo();
|
|
||||||
_delay_us(700);
|
|
||||||
place_bit1();
|
|
||||||
}
|
|
||||||
|
|
||||||
static inline void place_bit0(void)
|
|
||||||
{
|
|
||||||
data_lo();
|
|
||||||
_delay_us(65);
|
|
||||||
data_hi();
|
|
||||||
_delay_us(35);
|
|
||||||
}
|
|
||||||
|
|
||||||
static inline void place_bit1(void)
|
|
||||||
{
|
|
||||||
data_lo();
|
|
||||||
_delay_us(35);
|
|
||||||
data_hi();
|
|
||||||
_delay_us(65);
|
|
||||||
}
|
|
||||||
|
|
||||||
static inline void send_byte(uint8_t data)
|
|
||||||
{
|
|
||||||
for (int i = 0; i < 8; i++) {
|
|
||||||
if (data&(0x80>>i))
|
|
||||||
place_bit1();
|
|
||||||
else
|
|
||||||
place_bit0();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
static inline bool read_bit(void)
|
|
||||||
{
|
|
||||||
// ADB Bit Cells
|
// ADB Bit Cells
|
||||||
//
|
//
|
||||||
// bit cell time: 70-130us
|
// bit cell time: 70-130us
|
||||||
@ -245,47 +120,158 @@ static inline bool read_bit(void)
|
|||||||
// ______~~~~~~~~~~~~
|
// ______~~~~~~~~~~~~
|
||||||
// 39-52 78-91
|
// 39-52 78-91
|
||||||
//
|
//
|
||||||
// read:
|
|
||||||
// ________|~~~~~~~~~
|
|
||||||
// 55us
|
|
||||||
// Read data line after 55us. If data line is low/high then bit is 0/1.
|
|
||||||
// This method might not work at <90us bit cell time.
|
|
||||||
//
|
|
||||||
// [from Apple IIgs Hardware Reference Second Edition]
|
// [from Apple IIgs Hardware Reference Second Edition]
|
||||||
bool bit;
|
|
||||||
wait_data_lo(75); // wait the start of bit cell at least 130ms(55+0+75)
|
uint16_t adb_host_kbd_recv(void)
|
||||||
_delay_us(55);
|
{
|
||||||
bit = data_in();
|
uint16_t data = 0;
|
||||||
wait_data_hi(36); // wait high part of bit cell at least 91ms(55+36)
|
attention();
|
||||||
return bit;
|
send_byte(0x2C); // Addr:Keyboard(0010), Cmd:Talk(11), Register0(00)
|
||||||
|
place_bit0(); // Stopbit(0)
|
||||||
|
if (!wait_data_lo(500)) { // Tlt/Stop to Start(140-260us)
|
||||||
|
return 0; // No data to send
|
||||||
}
|
}
|
||||||
|
|
||||||
static inline uint8_t read_byte(void)
|
// ad hoc fix: without block inerrupt read wrong bit occasionally and get keys stuck
|
||||||
{
|
// TODO: is this needed anymore with improved timing?
|
||||||
uint8_t data = 0;
|
//cli();
|
||||||
for (int i = 0; i < 8; i++) {
|
uint8_t n = 17; // start bit + 16 data bits
|
||||||
|
do {
|
||||||
|
uint8_t lo = (uint8_t) wait_data_hi(130);
|
||||||
|
if (!lo)
|
||||||
|
goto error;
|
||||||
|
|
||||||
|
uint8_t hi = (uint8_t) wait_data_lo(lo);
|
||||||
|
if (!hi)
|
||||||
|
goto error;
|
||||||
|
|
||||||
|
hi = lo - hi;
|
||||||
|
lo = 130 - lo;
|
||||||
|
|
||||||
data <<= 1;
|
data <<= 1;
|
||||||
if (read_bit())
|
if (lo < hi) {
|
||||||
data = data | 1;
|
data |= 1;
|
||||||
}
|
}
|
||||||
|
else if (n == 17) {
|
||||||
|
// Service Request
|
||||||
|
dprintf("Startbit ERROR\n");
|
||||||
|
sei();
|
||||||
|
return -2;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
while ( --n );
|
||||||
|
|
||||||
|
// Stop bit can't be checked normally since it could have service request lenghtening
|
||||||
|
// and its high state never goes low.
|
||||||
|
if (!wait_data_hi(351) || wait_data_lo(91)) {
|
||||||
|
dprintf("Stopbit ERROR\n");
|
||||||
|
sei();
|
||||||
|
return -3;
|
||||||
|
}
|
||||||
|
sei();
|
||||||
return data;
|
return data;
|
||||||
|
|
||||||
|
error:
|
||||||
|
dprintf("Bit ERROR\n");
|
||||||
|
sei();
|
||||||
|
return -4;
|
||||||
}
|
}
|
||||||
|
|
||||||
static inline uint8_t wait_data_lo(uint16_t us)
|
void adb_host_listen(uint8_t cmd, uint8_t data_h, uint8_t data_l)
|
||||||
{
|
{
|
||||||
while (data_in() && us) {
|
attention();
|
||||||
_delay_us(1);
|
send_byte(cmd);
|
||||||
us--;
|
place_bit0(); // Stopbit(0)
|
||||||
|
_delay_us(200); // Tlt/Stop to Start
|
||||||
|
place_bit1(); // Startbit(1)
|
||||||
|
send_byte(data_h);
|
||||||
|
send_byte(data_l);
|
||||||
|
place_bit0(); // Stopbit(0);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// send state of LEDs
|
||||||
|
void adb_host_kbd_led(uint8_t led)
|
||||||
|
{
|
||||||
|
// Addr:Keyboard(0010), Cmd:Listen(10), Register2(10)
|
||||||
|
// send upper byte (not used)
|
||||||
|
// send lower byte (bit2: ScrollLock, bit1: CapsLock, bit0:
|
||||||
|
adb_host_listen(0x2A,0,led&0x07);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
#ifdef ADB_PSW_BIT
|
||||||
|
static inline void psw_lo()
|
||||||
|
{
|
||||||
|
ADB_DDR |= (1<<ADB_PSW_BIT);
|
||||||
|
ADB_PORT &= ~(1<<ADB_PSW_BIT);
|
||||||
|
}
|
||||||
|
static inline void psw_hi()
|
||||||
|
{
|
||||||
|
ADB_PORT |= (1<<ADB_PSW_BIT);
|
||||||
|
ADB_DDR &= ~(1<<ADB_PSW_BIT);
|
||||||
|
}
|
||||||
|
static inline bool psw_in()
|
||||||
|
{
|
||||||
|
ADB_PORT |= (1<<ADB_PSW_BIT);
|
||||||
|
ADB_DDR &= ~(1<<ADB_PSW_BIT);
|
||||||
|
return ADB_PIN&(1<<ADB_PSW_BIT);
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
static inline void attention(void)
|
||||||
|
{
|
||||||
|
data_lo();
|
||||||
|
_delay_us(800-35); // bit1 holds lo for 35 more
|
||||||
|
place_bit1();
|
||||||
|
}
|
||||||
|
|
||||||
|
static inline void place_bit0(void)
|
||||||
|
{
|
||||||
|
data_lo();
|
||||||
|
_delay_us(65);
|
||||||
|
data_hi();
|
||||||
|
_delay_us(35);
|
||||||
|
}
|
||||||
|
|
||||||
|
static inline void place_bit1(void)
|
||||||
|
{
|
||||||
|
data_lo();
|
||||||
|
_delay_us(35);
|
||||||
|
data_hi();
|
||||||
|
_delay_us(65);
|
||||||
|
}
|
||||||
|
|
||||||
|
static inline void send_byte(uint8_t data)
|
||||||
|
{
|
||||||
|
for (int i = 0; i < 8; i++) {
|
||||||
|
if (data&(0x80>>i))
|
||||||
|
place_bit1();
|
||||||
|
else
|
||||||
|
place_bit0();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// These are carefully coded to take 6 cycles of overhead.
|
||||||
|
// inline asm approach became too convoluted
|
||||||
|
static inline uint16_t wait_data_lo(uint16_t us)
|
||||||
|
{
|
||||||
|
do {
|
||||||
|
if ( !data_in() )
|
||||||
|
break;
|
||||||
|
_delay_us(1 - (6 * 1000000.0 / F_CPU));
|
||||||
|
}
|
||||||
|
while ( --us );
|
||||||
return us;
|
return us;
|
||||||
}
|
}
|
||||||
|
|
||||||
static inline uint8_t wait_data_hi(uint8_t us)
|
static inline uint16_t wait_data_hi(uint16_t us)
|
||||||
{
|
{
|
||||||
while (!data_in() && us) {
|
do {
|
||||||
_delay_us(1);
|
if ( data_in() )
|
||||||
us--;
|
break;
|
||||||
|
_delay_us(1 - (6 * 1000000.0 / F_CPU));
|
||||||
}
|
}
|
||||||
|
while ( --us );
|
||||||
return us;
|
return us;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Loading…
Reference in New Issue
Block a user