You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
This repo is archived. You can view files and clone it, but cannot push or open issues/pull-requests.

ibm4704.c 4.6KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189
  1. /*
  2. Copyright 2010,2011,2012,2013 Jun WAKO <[email protected]>
  3. */
  4. #include <stdbool.h>
  5. #include <util/delay.h>
  6. #include "debug.h"
  7. #include "ring_buffer.h"
  8. #include "ibm4704.h"
  9. #define WAIT(stat, us, err) do { \
  10. if (!wait_##stat(us)) { \
  11. ibm4704_error = err; \
  12. goto ERROR; \
  13. } \
  14. } while (0)
  15. uint8_t ibm4704_error = 0;
  16. void ibm4704_init(void)
  17. {
  18. inhibit(); // keep keyboard from sending
  19. IBM4704_INT_INIT();
  20. IBM4704_INT_ON();
  21. idle(); // allow keyboard sending
  22. }
  23. /*
  24. Host to Keyboard
  25. ----------------
  26. Data bits are LSB first and Parity is odd. Clock has around 60us high and 30us low part.
  27. ____ __ __ __ __ __ __ __ __ __ ________
  28. Clock \______/ \_/ \_/ \_/ \_/ \_/ \_/ \_/ \_/ \_/
  29. ^ ____ ____ ____ ____ ____ ____ ____ ____ ____ ____ ___
  30. Data ____|__/ X____X____X____X____X____X____X____X____X____X \___
  31. | Start 0 1 2 3 4 5 6 7 P Stop
  32. Request by host
  33. Start bit: can be long as 300-350us.
  34. Request: Host pulls Clock line down to request to send a command.
  35. Timing: After Request keyboard pull up Data and down Clock line to low for start bit.
  36. After request host release Clock line once Data line becomes hi.
  37. Host writes a bit while Clock is hi and Keyboard reads while low.
  38. Stop bit: Host releases or pulls up Data line to hi after 9th clock and waits for keyboard pull down the line to lo.
  39. */
  40. uint8_t ibm4704_send(uint8_t data)
  41. {
  42. bool parity = true; // odd parity
  43. ibm4704_error = 0;
  44. IBM4704_INT_OFF();
  45. /* Request to send */
  46. idle();
  47. clock_lo();
  48. /* wait for Start bit(Clock:lo/Data:hi) */
  49. WAIT(data_hi, 300, 0x30);
  50. /* Data bit */
  51. for (uint8_t i = 0; i < 8; i++) {
  52. WAIT(clock_hi, 100, 0x40+i);
  53. if (data&(1<<i)) {
  54. parity = !parity;
  55. data_hi();
  56. } else {
  57. data_lo();
  58. }
  59. WAIT(clock_lo, 100, 0x48+i);
  60. }
  61. /* Parity bit */
  62. WAIT(clock_hi, 100, 0x34);
  63. if (parity) { data_hi(); } else { data_lo(); }
  64. WAIT(clock_lo, 100, 0x35);
  65. /* Stop bit */
  66. WAIT(clock_hi, 100, 0x34);
  67. data_hi();
  68. /* End */
  69. WAIT(data_lo, 100, 0x36);
  70. idle();
  71. IBM4704_INT_ON();
  72. return 0;
  73. ERROR:
  74. idle();
  75. if (ibm4704_error > 0x30) {
  76. xprintf("S:%02X ", ibm4704_error);
  77. }
  78. IBM4704_INT_ON();
  79. return -1;
  80. }
  81. /* wait forever to receive data */
  82. uint8_t ibm4704_recv_response(void)
  83. {
  84. while (!rbuf_has_data()) {
  85. _delay_ms(1);
  86. }
  87. return rbuf_dequeue();
  88. }
  89. uint8_t ibm4704_recv(void)
  90. {
  91. if (rbuf_has_data()) {
  92. return rbuf_dequeue();
  93. } else {
  94. return -1;
  95. }
  96. }
  97. /*
  98. Keyboard to Host
  99. ----------------
  100. Data bits are LSB first and Parity is odd. Clock has around 60us high and 30us low part.
  101. ____ __ __ __ __ __ __ __ __ __ _______
  102. Clock \_____/ \_/ \_/ \_/ \_/ \_/ \_/ \_/ \_/ \_/
  103. ____ ____ ____ ____ ____ ____ ____ ____ ____ ____
  104. Data ____/ X____X____X____X____X____X____X____X____X____X________
  105. Start 0 1 2 3 4 5 6 7 P Stop
  106. Start bit: can be long as 300-350us.
  107. Inhibit: Pull Data line down to inhibit keyboard to send.
  108. Timing: Host reads bit while Clock is hi.(rising edge)
  109. Stop bit: Keyboard pulls down Data line to lo after 9th clock.
  110. */
  111. ISR(IBM4704_INT_VECT)
  112. {
  113. static enum {
  114. BIT0, BIT1, BIT2, BIT3, BIT4, BIT5, BIT6, BIT7, PARITY, STOP
  115. } state = BIT0;
  116. // LSB first
  117. static uint8_t data = 0;
  118. // Odd parity
  119. static uint8_t parity = false;
  120. ibm4704_error = 0;
  121. switch (state) {
  122. case BIT0:
  123. case BIT1:
  124. case BIT2:
  125. case BIT3:
  126. case BIT4:
  127. case BIT5:
  128. case BIT6:
  129. case BIT7:
  130. data >>= 1;
  131. if (data_in()) {
  132. data |= 0x80;
  133. parity = !parity;
  134. }
  135. break;
  136. case PARITY:
  137. if (data_in()) {
  138. parity = !parity;
  139. }
  140. if (!parity)
  141. goto ERROR;
  142. break;
  143. case STOP:
  144. // Data:Low
  145. WAIT(data_lo, 100, state);
  146. rbuf_enqueue(data);
  147. ibm4704_error = IBM4704_ERR_NONE;
  148. goto DONE;
  149. break;
  150. default:
  151. goto ERROR;
  152. }
  153. state++;
  154. goto RETURN;
  155. ERROR:
  156. ibm4704_error = state;
  157. while (ibm4704_send(0xFE)) _delay_ms(1); // resend
  158. xprintf("R:%02X%02X\n", state, data);
  159. DONE:
  160. state = BIT0;
  161. data = 0;
  162. parity = false;
  163. RETURN:
  164. return;
  165. }