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.

183 lines
4.7 KiB

9 years ago
  1. /*
  2. Copyright 2010,2011,2012,2013 Jun WAKO <wakojun@gmail.com>
  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) \
  10. do { \
  11. if (!wait_##stat(us)) { \
  12. ibm4704_error = err; \
  13. goto ERROR; \
  14. } \
  15. } while (0)
  16. uint8_t ibm4704_error = 0;
  17. void ibm4704_init(void) {
  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. bool parity = true; // odd parity
  42. ibm4704_error = 0;
  43. IBM4704_INT_OFF();
  44. /* Request to send */
  45. idle();
  46. clock_lo();
  47. /* wait for Start bit(Clock:lo/Data:hi) */
  48. WAIT(data_hi, 300, 0x30);
  49. /* Data bit */
  50. for (uint8_t i = 0; i < 8; i++) {
  51. WAIT(clock_hi, 100, 0x40 + i);
  52. if (data & (1 << i)) {
  53. parity = !parity;
  54. data_hi();
  55. } else {
  56. data_lo();
  57. }
  58. WAIT(clock_lo, 100, 0x48 + i);
  59. }
  60. /* Parity bit */
  61. WAIT(clock_hi, 100, 0x34);
  62. if (parity) {
  63. data_hi();
  64. } else {
  65. data_lo();
  66. }
  67. WAIT(clock_lo, 100, 0x35);
  68. /* Stop bit */
  69. WAIT(clock_hi, 100, 0x34);
  70. data_hi();
  71. /* End */
  72. WAIT(data_lo, 100, 0x36);
  73. idle();
  74. IBM4704_INT_ON();
  75. return 0;
  76. ERROR:
  77. idle();
  78. if (ibm4704_error > 0x30) {
  79. xprintf("S:%02X ", ibm4704_error);
  80. }
  81. IBM4704_INT_ON();
  82. return -1;
  83. }
  84. /* wait forever to receive data */
  85. uint8_t ibm4704_recv_response(void) {
  86. while (!rbuf_has_data()) {
  87. _delay_ms(1);
  88. }
  89. return rbuf_dequeue();
  90. }
  91. uint8_t ibm4704_recv(void) {
  92. if (rbuf_has_data()) {
  93. return rbuf_dequeue();
  94. } else {
  95. return -1;
  96. }
  97. }
  98. /*
  99. Keyboard to Host
  100. ----------------
  101. Data bits are LSB first and Parity is odd. Clock has around 60us high and 30us low part.
  102. ____ __ __ __ __ __ __ __ __ __ _______
  103. Clock \_____/ \_/ \_/ \_/ \_/ \_/ \_/ \_/ \_/ \_/
  104. ____ ____ ____ ____ ____ ____ ____ ____ ____ ____
  105. Data ____/ X____X____X____X____X____X____X____X____X____X________
  106. Start 0 1 2 3 4 5 6 7 P Stop
  107. Start bit: can be long as 300-350us.
  108. Inhibit: Pull Data line down to inhibit keyboard to send.
  109. Timing: Host reads bit while Clock is hi.(rising edge)
  110. Stop bit: Keyboard pulls down Data line to lo after 9th clock.
  111. */
  112. ISR(IBM4704_INT_VECT) {
  113. static enum { BIT0, BIT1, BIT2, BIT3, BIT4, BIT5, BIT6, BIT7, PARITY, STOP } state = BIT0;
  114. // LSB first
  115. static uint8_t data = 0;
  116. // Odd parity
  117. static uint8_t parity = false;
  118. ibm4704_error = 0;
  119. switch (state) {
  120. case BIT0:
  121. case BIT1:
  122. case BIT2:
  123. case BIT3:
  124. case BIT4:
  125. case BIT5:
  126. case BIT6:
  127. case BIT7:
  128. data >>= 1;
  129. if (data_in()) {
  130. data |= 0x80;
  131. parity = !parity;
  132. }
  133. break;
  134. case PARITY:
  135. if (data_in()) {
  136. parity = !parity;
  137. }
  138. if (!parity) goto ERROR;
  139. break;
  140. case STOP:
  141. // Data:Low
  142. WAIT(data_lo, 100, state);
  143. rbuf_enqueue(data);
  144. ibm4704_error = IBM4704_ERR_NONE;
  145. goto DONE;
  146. break;
  147. default:
  148. goto ERROR;
  149. }
  150. state++;
  151. goto RETURN;
  152. ERROR:
  153. ibm4704_error = state;
  154. while (ibm4704_send(0xFE)) _delay_ms(1); // resend
  155. xprintf("R:%02X%02X\n", state, data);
  156. DONE:
  157. state = BIT0;
  158. data = 0;
  159. parity = false;
  160. RETURN:
  161. return;
  162. }