nuclear@2: #include nuclear@2: #include nuclear@2: #include nuclear@2: #include "ps2kbd.h" nuclear@2: #include "defs.h" nuclear@3: #include "timer.h" nuclear@3: nuclear@3: #define TIMEOUT 100 nuclear@2: nuclear@2: #define BUF_SZ 16 nuclear@2: #define BUF_IDX_MASK (BUF_SZ - 1) nuclear@2: #define NEXT_IDX(x) (((x) + 1) & BUF_IDX_MASK) nuclear@2: static volatile unsigned char keybuf[BUF_SZ]; nuclear@2: static volatile unsigned char key_rd, key_wr; nuclear@2: nuclear@3: static volatile int send_nbits, wait_ack; nuclear@3: static volatile unsigned char send_val, send_par; nuclear@2: nuclear@3: static void abort_send(void); nuclear@3: nuclear@3: int ps2write(unsigned char c) nuclear@2: { nuclear@3: cli(); nuclear@3: send_nbits = 10; nuclear@3: send_val = c; nuclear@3: send_par = 0; /* init to 0, will be calculated while sending */ nuclear@2: nuclear@3: /* inhibit transmission, hold at least 100us */ nuclear@3: PORTD &= ~PCLK_BIT; nuclear@3: DDRD |= PCLK_BIT; nuclear@3: EIFR |= (1 << INTF0); /* clear pending interrupt due to clock transition */ nuclear@3: sei(); nuclear@3: _delay_us(100); nuclear@2: nuclear@3: /* RTS by data low & release clock (this counts as start bit?) */ nuclear@3: PORTD &= ~PDATA_BIT; nuclear@3: DDRD |= PDATA_BIT; nuclear@3: DDRD &= ~PCLK_BIT; nuclear@2: nuclear@3: reset_timer(); nuclear@3: while(send_nbits > 0) { nuclear@3: if(get_msec() > TIMEOUT) { nuclear@3: abort_send(); nuclear@3: return -1; nuclear@3: } nuclear@2: } nuclear@3: _delay_us(5); nuclear@2: nuclear@3: /* release data line and wait for ack */ nuclear@3: cli(); nuclear@3: wait_ack = 1; nuclear@3: sei(); nuclear@3: DDRD &= ~PDATA_BIT; nuclear@3: reset_timer(); nuclear@3: while(wait_ack) { nuclear@3: if(get_msec() > TIMEOUT) { nuclear@3: abort_send(); nuclear@3: return -1; nuclear@3: } nuclear@3: } nuclear@3: return 0; nuclear@3: } nuclear@3: nuclear@3: static void abort_send(void) nuclear@3: { nuclear@3: cli(); nuclear@3: send_nbits = 0; nuclear@3: wait_ack = 0; nuclear@3: /* hold clock low for 100us */ nuclear@3: PORTD &= ~PCLK_BIT; nuclear@3: DDRD |= PCLK_BIT; nuclear@3: _delay_us(100); nuclear@3: DDRD &= ~(PCLK_BIT | PDATA_BIT); nuclear@3: EIFR |= (1 << INTF0); /* clear pending interrupt */ nuclear@3: sei(); nuclear@2: } nuclear@2: nuclear@2: unsigned char ps2read(void) nuclear@2: { nuclear@2: unsigned char key; nuclear@2: nuclear@2: while(key_rd == key_wr) { nuclear@2: } nuclear@2: nuclear@2: cli(); nuclear@2: key = keybuf[key_rd]; nuclear@2: key_rd = NEXT_IDX(key_rd); nuclear@2: sei(); nuclear@2: nuclear@2: return key; nuclear@2: } nuclear@2: nuclear@2: int ps2pending(void) nuclear@2: { nuclear@2: return key_rd != key_wr; nuclear@2: } nuclear@2: nuclear@3: int ps2wait(unsigned int timeout) nuclear@3: { nuclear@3: reset_timer(); nuclear@3: while(key_rd == key_wr) { nuclear@3: if(get_msec() >= timeout) return -1; nuclear@3: } nuclear@3: return 0; nuclear@3: } nuclear@3: nuclear@3: #define PS2_ACK 0xfa nuclear@3: #define PS2_RESEND 0xfe nuclear@3: #define PS2_ECHO 0xee nuclear@3: nuclear@3: int ps2setled(unsigned char state) nuclear@3: { nuclear@3: unsigned char c; nuclear@3: nuclear@3: ps2write(0xed); nuclear@3: reset_timer(); nuclear@3: while(!ps2pending()) { nuclear@3: if(get_msec() >= TIMEOUT) return -1; nuclear@3: } nuclear@3: c = ps2read(); nuclear@3: /*printf("ps2setled 1st response: %x\r\n", (unsigned int)c);*/ nuclear@3: if(c != PS2_ACK) return -1; nuclear@3: nuclear@3: ps2write(state); nuclear@3: reset_timer(); nuclear@3: while(!ps2pending()) { nuclear@3: if(get_msec() >= TIMEOUT) return -1; nuclear@3: } nuclear@3: c = ps2read(); nuclear@3: /*printf("ps2setled 2nd response: %x\r\n", (unsigned int)c);*/ nuclear@3: if(c != PS2_ACK) return -1; nuclear@3: nuclear@3: return 0; nuclear@3: } nuclear@3: nuclear@2: ISR(INT0_vect) nuclear@2: { nuclear@2: static unsigned char value, parity; nuclear@2: /*static unsigned char valp;*/ nuclear@2: static int nbits; nuclear@2: nuclear@3: if(wait_ack) { nuclear@3: if(!(PIND & PDATA_BIT)) { nuclear@3: wait_ack = 0; nuclear@3: } nuclear@3: return; nuclear@3: } nuclear@3: nuclear@3: if(send_nbits > 0) { nuclear@3: --send_nbits; nuclear@3: switch(send_nbits) { nuclear@3: case 1: /* parity bit */ nuclear@3: if(send_par & 1) { /* odd number of ones: parity 0 */ nuclear@3: PORTD &= ~PDATA_BIT; nuclear@3: } else { /* even number of ones: parity 1 */ nuclear@3: PORTD |= PDATA_BIT; nuclear@3: } nuclear@3: break; nuclear@3: case 0: /* stop bit: 1 */ nuclear@3: PORTD |= PDATA_BIT; nuclear@3: break; nuclear@3: default: nuclear@3: if(send_val & 1) { nuclear@3: PORTD |= PDATA_BIT; nuclear@3: ++send_par; nuclear@3: } else { nuclear@3: PORTD &= ~PDATA_BIT; nuclear@3: } nuclear@3: send_val >>= 1; nuclear@3: } nuclear@3: nuclear@2: } else { nuclear@2: if(nbits > 0 && nbits < 9) { nuclear@2: value >>= 1; nuclear@2: if(PIND & PDATA_BIT) { nuclear@2: value |= 0x80; nuclear@2: parity ^= 1; nuclear@2: } nuclear@2: }/* else if(nbits == 9) { nuclear@2: valp = (PIND >> PDATA) & 1; nuclear@2: }*/ nuclear@2: if(++nbits >= 11) { nuclear@2: nbits = 0; nuclear@2: nuclear@2: /* check parity */ nuclear@2: /*if((parity & 1) == (valp & 1)) {}*/ nuclear@2: keybuf[key_wr] = (unsigned char)value; nuclear@2: key_wr = NEXT_IDX(key_wr); nuclear@2: nuclear@2: value = 0; nuclear@2: parity = 0; nuclear@2: } nuclear@2: } nuclear@2: }