Du kan inte välja fler än 25 ämnen Ämnen måste starta med en bokstav eller siffra, kan innehålla bindestreck ('-') och vara max 35 tecken långa.
This repo is archived. You can view files and clone it, but cannot push or open issues/pull-requests.

ibm4704.c 4.6KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190
  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. IBM4704_INT_INIT();
  19. IBM4704_INT_ON();
  20. idle();
  21. }
  22. /*
  23. Host to Keyboard
  24. ----------------
  25. Data bits are LSB first and Parity is odd. Clock has around 60us high and 30us low part.
  26. ____ __ __ __ __ __ __ __ __ __ ________
  27. Clock \______/ \_/ \_/ \_/ \_/ \_/ \_/ \_/ \_/ \_/
  28. ^ ____ ____ ____ ____ ____ ____ ____ ____ ____ ____ ___
  29. Data ____|__/ X____X____X____X____X____X____X____X____X____X \___
  30. | Start 0 1 2 3 4 5 6 7 P Stop
  31. Request by host
  32. Start bit: can be long as 300-350us.
  33. Request: Host pulls Clock line down to request to send a command.
  34. Timing: After Request keyboard pull up Data and down Clock line to low for start bit.
  35. After request host release Clock line once Data line becomes hi.
  36. Host writes a bit while Clock is hi and Keyboard reads while low.
  37. Stop bit: Host releases or pulls up Data line to hi after 9th clock and waits for keyboard pull down the line to lo.
  38. */
  39. uint8_t ibm4704_send(uint8_t data)
  40. {
  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) { data_hi(); } else { data_lo(); }
  63. WAIT(clock_lo, 100, 0x35);
  64. /* Stop bit */
  65. WAIT(clock_hi, 100, 0x34);
  66. data_hi();
  67. /* End */
  68. WAIT(data_lo, 100, 0x36);
  69. idle();
  70. IBM4704_INT_ON();
  71. return 0;
  72. ERROR:
  73. idle();
  74. if (ibm4704_error > 0x30) {
  75. xprintf("S:%02X ", ibm4704_error);
  76. }
  77. IBM4704_INT_ON();
  78. return -1;
  79. }
  80. /* wait forever to receive data */
  81. uint8_t ibm4704_recv_response(void)
  82. {
  83. while (!rbuf_has_data()) {
  84. _delay_ms(1);
  85. }
  86. return rbuf_dequeue();
  87. }
  88. /*
  89. Keyboard to Host
  90. ----------------
  91. Data bits are LSB first and Parity is odd. Clock has around 60us high and 30us low part.
  92. ____ __ __ __ __ __ __ __ __ __ ________
  93. Clock \____/ \_/ \_/ \_/ \_/ \_/ \_/ \_/ \_/ \_/
  94. ____ ____ ____ ____ ____ ____ ____ ____ ____ ____
  95. Data ____/ X____X____X____X____X____X____X____X____X____X________
  96. Start 0 1 2 3 4 5 6 7 P Stop
  97. Start bit: can be long as 300-350us.
  98. Inhibit: Pull Data line down to inhibit keyboard to send.
  99. Timing: Host reads bit while Clock is hi.
  100. Stop bit: Keyboard pulls down Data line to lo after 9th clock.
  101. */
  102. uint8_t ibm4704_recv(void)
  103. {
  104. if (rbuf_has_data()) {
  105. return rbuf_dequeue();
  106. } else {
  107. return -1;
  108. }
  109. }
  110. ISR(IBM4704_INT_VECT)
  111. {
  112. static enum {
  113. INIT, START, BIT0, BIT1, BIT2, BIT3, BIT4, BIT5, BIT6, BIT7, PARITY,
  114. } state = INIT;
  115. // LSB first
  116. static uint8_t data = 0;
  117. // Odd parity
  118. static uint8_t parity = false;
  119. ibm4704_error = 0;
  120. // return unless falling edge
  121. if (clock_in()) { goto RETURN; } // why this occurs?
  122. state++;
  123. switch (state) {
  124. case START:
  125. // Data:Low
  126. WAIT(data_hi, 10, state);
  127. break;
  128. case BIT0:
  129. case BIT1:
  130. case BIT2:
  131. case BIT3:
  132. case BIT4:
  133. case BIT5:
  134. case BIT6:
  135. case BIT7:
  136. data >>= 1;
  137. if (data_in()) {
  138. data |= 0x80;
  139. parity = !parity;
  140. }
  141. break;
  142. case PARITY:
  143. if (data_in()) {
  144. parity = !parity;
  145. }
  146. if (!parity)
  147. goto ERROR;
  148. rbuf_enqueue(data);
  149. ibm4704_error = IBM4704_ERR_NONE;
  150. goto DONE;
  151. break;
  152. default:
  153. goto ERROR;
  154. }
  155. goto RETURN;
  156. ERROR:
  157. ibm4704_error = state;
  158. while (ibm4704_send(0xFE)) _delay_ms(1); // resend
  159. xprintf("R:%02X%02X\n", state, data);
  160. DONE:
  161. state = INIT;
  162. data = 0;
  163. parity = false;
  164. RETURN:
  165. return;
  166. }