nuclear@2: #include nuclear@2: #include nuclear@2: #include nuclear@2: #include nuclear@2: #include "amigakb.h" nuclear@2: #include "defs.h" nuclear@2: #include "timer.h" nuclear@2: nuclear@2: #define TIMEOUT_MSEC 143 nuclear@2: nuclear@2: static void resync(void); nuclear@2: nuclear@2: void amikb_sendkey(unsigned char keycode, int press) nuclear@2: { nuclear@2: int i; nuclear@2: static unsigned char prev_keycode = 0xff; nuclear@2: nuclear@2: /* keycode bit transfer order: 6 5 4 3 2 1 0 7 (7 is pressed flag) */ nuclear@2: keycode = (keycode << 1) | (~press & 1); nuclear@2: if(keycode == prev_keycode) return; nuclear@2: prev_keycode = keycode; nuclear@2: nuclear@2: /* make sure we don't pulse the lines while grabbing control nuclear@2: * by first reinstating the pullups before changing direction nuclear@2: */ nuclear@2: PORTD |= ACLK_BIT | ADATA_BIT; nuclear@2: DDRD |= ACLK_BIT | ADATA_BIT; nuclear@2: nuclear@2: /* pulse the data line and wait for about 100us */ nuclear@2: PORTD &= ~ADATA_BIT; nuclear@2: _delay_us(20); nuclear@2: PORTD |= ADATA_BIT; nuclear@2: _delay_us(100); nuclear@2: nuclear@2: for(i=0; i<8; i++) { nuclear@2: /* data line is inverted */ nuclear@2: if(keycode & 0x80) { nuclear@2: PORTD &= ~ADATA_BIT; nuclear@2: } else { nuclear@2: PORTD |= ADATA_BIT; nuclear@2: } nuclear@2: keycode <<= 1; nuclear@2: _delay_us(20); nuclear@2: /* pulse the clock */ nuclear@2: cli(); nuclear@2: PORTD &= ~ACLK_BIT; nuclear@2: EIFR |= (1 << INTF1); nuclear@2: sei(); nuclear@2: _delay_us(20); nuclear@2: PORTD |= ACLK_BIT; nuclear@2: _delay_us(20); nuclear@2: } nuclear@2: nuclear@2: /* similarly tristate first, then drop the pullups */ nuclear@2: DDRD &= ~(ACLK_BIT | ADATA_BIT); nuclear@2: PORTD &= ~(ACLK_BIT | ADATA_BIT); nuclear@2: nuclear@2: /* wait for ack */ nuclear@2: reset_timer(); nuclear@2: while(PIND & ADATA_BIT) { nuclear@2: if(get_msec() >= TIMEOUT_MSEC) { nuclear@2: resync(); nuclear@2: break; nuclear@2: } nuclear@2: } nuclear@2: } nuclear@2: nuclear@2: void amikb_reset(void) nuclear@2: { nuclear@2: cli(); nuclear@2: PORTD &= ~ARST_BIT; nuclear@2: DDRD |= ARST_BIT; nuclear@2: _delay_ms(10); nuclear@2: PORTD |= ARST_BIT; nuclear@2: DDRD &= ~ARST_BIT; nuclear@2: sei(); nuclear@2: } nuclear@2: nuclear@2: static void resync(void) nuclear@2: { nuclear@2: PORTD |= ACLK_BIT | ADATA_BIT; nuclear@2: printf("lost sync\r\n"); nuclear@2: nuclear@2: for(;;) { nuclear@2: cli(); nuclear@2: DDRD |= ACLK_BIT | ADATA_BIT; nuclear@2: nuclear@2: PORTD &= ~ACLK_BIT; nuclear@2: EIFR |= (1 << INTF1); /* clear interrupt raised by the previous line */ nuclear@2: sei(); nuclear@2: _delay_us(20); nuclear@2: PORTD |= ACLK_BIT; nuclear@2: nuclear@2: DDRD &= ~(ACLK_BIT | ADATA_BIT); nuclear@2: nuclear@2: reset_timer(); nuclear@2: while(get_msec() < TIMEOUT_MSEC) { nuclear@2: if(!(PIND & ADATA_BIT)) { nuclear@2: return; nuclear@2: } nuclear@2: } nuclear@2: } nuclear@2: } nuclear@2: nuclear@2: static void handle_cmd(unsigned char cmd) nuclear@2: { nuclear@2: printf("amikbd got cmd: %x\r\n", (unsigned int)cmd); nuclear@2: } nuclear@2: nuclear@2: ISR(INT1_vect) nuclear@2: { nuclear@2: static unsigned char value; nuclear@2: static int nbits; nuclear@2: nuclear@2: value <<= 1; nuclear@2: if(PIND & ADATA_BIT) { nuclear@2: value |= 1; nuclear@2: } nuclear@2: if(++nbits >= 8) { nuclear@2: handle_cmd(value); nuclear@2: nbits = 0; nuclear@2: value = 0; nuclear@2: } nuclear@2: }