Keyboard firmwares for Atmel AVR and Cortex-M
Nelze vybrat více než 25 témat Téma musí začínat písmenem nebo číslem, může obsahovat pomlčky („-“) a může být dlouhé až 35 znaků.

ibm4704.c 4.5KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187
  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. uint8_t ibm4704_recv(void)
  89. {
  90. if (rbuf_has_data()) {
  91. return rbuf_dequeue();
  92. } else {
  93. return -1;
  94. }
  95. }
  96. /*
  97. Keyboard to Host
  98. ----------------
  99. Data bits are LSB first and Parity is odd. Clock has around 60us high and 30us low part.
  100. ____ __ __ __ __ __ __ __ __ __ _______
  101. Clock \_____/ \_/ \_/ \_/ \_/ \_/ \_/ \_/ \_/ \_/
  102. ____ ____ ____ ____ ____ ____ ____ ____ ____ ____
  103. Data ____/ X____X____X____X____X____X____X____X____X____X________
  104. Start 0 1 2 3 4 5 6 7 P Stop
  105. Start bit: can be long as 300-350us.
  106. Inhibit: Pull Data line down to inhibit keyboard to send.
  107. Timing: Host reads bit while Clock is hi.(rising edge)
  108. Stop bit: Keyboard pulls down Data line to lo after 9th clock.
  109. */
  110. ISR(IBM4704_INT_VECT)
  111. {
  112. static enum {
  113. STOP, BIT0, BIT1, BIT2, BIT3, BIT4, BIT5, BIT6, BIT7, PARITY
  114. } state = STOP;
  115. // LSB first
  116. static uint8_t data = 0;
  117. // Odd parity
  118. static uint8_t parity = false;
  119. ibm4704_error = 0;
  120. switch (state++) {
  121. case STOP:
  122. // Data:Low
  123. WAIT(data_lo, 10, state);
  124. break;
  125. case BIT0:
  126. case BIT1:
  127. case BIT2:
  128. case BIT3:
  129. case BIT4:
  130. case BIT5:
  131. case BIT6:
  132. case BIT7:
  133. data >>= 1;
  134. if (data_in()) {
  135. data |= 0x80;
  136. parity = !parity;
  137. }
  138. break;
  139. case PARITY:
  140. if (data_in()) {
  141. parity = !parity;
  142. }
  143. if (!parity)
  144. goto ERROR;
  145. rbuf_enqueue(data);
  146. ibm4704_error = IBM4704_ERR_NONE;
  147. goto DONE;
  148. break;
  149. default:
  150. goto ERROR;
  151. }
  152. goto RETURN;
  153. ERROR:
  154. ibm4704_error = state;
  155. while (ibm4704_send(0xFE)) _delay_ms(1); // resend
  156. xprintf("R:%02X%02X\n", state, data);
  157. DONE:
  158. state = STOP;
  159. data = 0;
  160. parity = false;
  161. RETURN:
  162. return;
  163. }