// TODO: send using interrupt if available uint8_t ps2_host_send(uint8_t data) { uint8_t res = 0; bool parity = true; ps2_error = PS2_ERR_NONE; #ifdef PS2_USE_INT PS2_INT_OFF(); #endif /* terminate a transmission if we have */ inhibit(); _delay_us(200); // at least 100us /* start bit [1] */ data_lo(); clock_hi(); WAIT(clock_lo, 20000, 10); // may take 15ms at most until device starts clocking /* data [2-9] */ for (uint8_t i = 0; i < 8; i++) { _delay_us(15); if (data&(1<<i)) { parity = !parity; data_hi(); } else { data_lo(); } WAIT(clock_hi, 50, 2); WAIT(clock_lo, 50, 3); } /* parity [10] */ _delay_us(15); if (parity) { data_hi(); } else { data_lo(); } WAIT(clock_hi, 50, 4); WAIT(clock_lo, 50, 5); /* stop bit [11] */ _delay_us(15); data_hi(); /* ack [12] */ WAIT(data_lo, 50, 6); WAIT(clock_lo, 50, 7); /* wait for idle state */ WAIT(clock_hi, 50, 8); WAIT(data_hi, 50, 9); #ifdef PS2_USE_INT PS2_INT_ON(); #endif res = ps2_host_recv_response(); ERROR: #ifdef PS2_USE_INT PS2_INT_ON(); idle(); #else inhibit(); #endif return res; }
uint8_t ps2_host_send(uint8_t data) { bool parity = true; ps2_error = PS2_ERR_NONE; PS2_USART_OFF(); /* terminate a transmission if we have */ inhibit(); _delay_us(100); // [4]p.13 /* 'Request to Send' and Start bit */ data_lo(); clock_hi(); WAIT(clock_lo, 10000, 10); // 10ms [5]p.50 /* Data bit[2-9] */ for (uint8_t i = 0; i < 8; i++) { _delay_us(15); if (data&(1<<i)) { parity = !parity; data_hi(); } else { data_lo(); } WAIT(clock_hi, 50, 2); WAIT(clock_lo, 50, 3); } /* Parity bit */ _delay_us(15); if (parity) { data_hi(); } else { data_lo(); } WAIT(clock_hi, 50, 4); WAIT(clock_lo, 50, 5); /* Stop bit */ _delay_us(15); data_hi(); /* Ack */ WAIT(data_lo, 50, 6); WAIT(clock_lo, 50, 7); /* wait for idle state */ WAIT(clock_hi, 50, 8); WAIT(data_hi, 50, 9); idle(); PS2_USART_INIT(); PS2_USART_RX_INT_ON(); return ps2_host_recv_response(); ERROR: idle(); PS2_USART_INIT(); PS2_USART_RX_INT_ON(); return 0; }
/* Host to Keyboard ---------------- Data bits are LSB first and Parity is odd. Clock has around 60us high and 30us low part. ____ __ __ __ __ __ __ __ __ __ ________ Clock \______/ \_/ \_/ \_/ \_/ \_/ \_/ \_/ \_/ \_/ ^ ____ ____ ____ ____ ____ ____ ____ ____ ____ ____ ___ Data ____|__/ X____X____X____X____X____X____X____X____X____X \___ | Start 0 1 2 3 4 5 6 7 P Stop Request by host Start bit: can be long as 300-350us. Request: Host pulls Clock line down to request to send a command. Timing: After Request keyboard pull up Data and down Clock line to low for start bit. After request host release Clock line once Data line becomes hi. Host writes a bit while Clock is hi and Keyboard reads while low. Stop bit: Host releases or pulls up Data line to hi after 9th clock and waits for keyboard pull down the line to lo. */ uint8_t ibm4704_send(uint8_t data) { bool parity = true; // odd parity ibm4704_error = 0; IBM4704_INT_OFF(); /* Request to send */ idle(); clock_lo(); /* wait for Start bit(Clock:lo/Data:hi) */ WAIT(data_hi, 300, 0x30); /* Data bit */ for (uint8_t i = 0; i < 8; i++) { WAIT(clock_hi, 100, 0x40+i); if (data&(1<<i)) { parity = !parity; data_hi(); } else { data_lo(); } WAIT(clock_lo, 100, 0x48+i); } /* Parity bit */ WAIT(clock_hi, 100, 0x34); if (parity) { data_hi(); } else { data_lo(); } WAIT(clock_lo, 100, 0x35); /* Stop bit */ WAIT(clock_hi, 100, 0x34); data_hi(); /* End */ WAIT(data_lo, 100, 0x36); idle(); IBM4704_INT_ON(); return 0; ERROR: idle(); if (ibm4704_error > 0x30) { xprintf("S:%02X ", ibm4704_error); } IBM4704_INT_ON(); return -1; }
uint8_t m0110_send(uint8_t data) { m0110_error = 0; request(); WAIT_MS(clock_lo, 250, 1); // keyboard may block long time for (uint8_t bit = 0x80; bit; bit >>= 1) { WAIT_US(clock_lo, 250, 3); if (data&bit) { data_hi(); } else { data_lo(); } WAIT_US(clock_hi, 200, 4); } _delay_us(100); // hold last bit for 80us idle(); return 1; ERROR: print("m0110_send err: "); phex(m0110_error); print("\n"); _delay_ms(500); idle(); return 0; }
static inline void idle(void) { clock_hi(); data_hi(); }
/* inhibit device to send */ static inline void inhibit(void) { clock_lo(); data_hi(); }