Keyboard firmwares for Atmel AVR and Cortex-M
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.

ibm4704.c 4.4KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169
  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 "ibm4704.h"
  8. #define WAIT(stat, us, err) do { \
  9. if (!wait_##stat(us)) { \
  10. ibm4704_error = err; \
  11. goto ERROR; \
  12. } \
  13. } while (0)
  14. uint8_t ibm4704_error = 0;
  15. void ibm4704_init(void)
  16. {
  17. inhibit();
  18. }
  19. /*
  20. Host to Keyboard
  21. ----------------
  22. Data bits are LSB first and Parity is odd. Clock has around 60us high and 30us low part.
  23. ____ __ __ __ __ __ __ __ __ __ ________
  24. Clock \______/ \_/ \_/ \_/ \_/ \_/ \_/ \_/ \_/ \_/
  25. ^ ____ ____ ____ ____ ____ ____ ____ ____ ____ ____ ___
  26. Data ____|__/ X____X____X____X____X____X____X____X____X____X \___
  27. | Start 0 1 2 3 4 5 6 7 P Stop
  28. Request by host
  29. Start bit: can be long as 300-350us.
  30. Request: Host pulls Clock line down to request to send a command.
  31. Timing: After Request keyboard pull up Data and down Clock line to low for start bit.
  32. After request host release Clock line once Data line becomes hi.
  33. Host writes a bit while Clock is hi and Keyboard reads while low.
  34. Stop bit: Host releases or pulls up Data line to hi after 9th clock and waits for keyboard pull down the line to lo.
  35. */
  36. uint8_t ibm4704_send(uint8_t data)
  37. {
  38. bool parity = true; // odd parity
  39. ibm4704_error = 0;
  40. /* Request to send */
  41. idle();
  42. clock_lo();
  43. /* wait for Start bit(Clock:lo/Data:hi) */
  44. WAIT(data_hi, 300, 0x30);
  45. /* Data bit */
  46. for (uint8_t i = 0; i < 8; i++) {
  47. WAIT(clock_hi, 100, 0x40+i);
  48. //_delay_us(5);
  49. if (data&(1<<i)) {
  50. parity = !parity;
  51. data_hi();
  52. } else {
  53. data_lo();
  54. }
  55. WAIT(clock_lo, 100, 0x48+i);
  56. }
  57. /* Parity bit */
  58. WAIT(clock_hi, 100, 0x34);
  59. if (parity) { data_hi(); } else { data_lo(); }
  60. WAIT(clock_lo, 100, 0x35);
  61. /* Stop bit */
  62. WAIT(clock_hi, 100, 0x34);
  63. data_hi();
  64. /* End */
  65. WAIT(data_lo, 100, 0x36);
  66. inhibit();
  67. _delay_us(200); // wait to recover clock to hi
  68. return 0;
  69. ERROR:
  70. inhibit();
  71. if (ibm4704_error >= 0x30) {
  72. xprintf("x%02X ", ibm4704_error);
  73. }
  74. _delay_us(200); // wait to recover clock to hi
  75. return -1;
  76. }
  77. /* receive data when host want else inhibit communication */
  78. uint8_t ibm4704_recv_response(void)
  79. {
  80. // 250 * 100us(wait start bit in ibm4704_recv)
  81. uint8_t data = 0;
  82. uint8_t try = 250;
  83. do {
  84. data = ibm4704_recv();
  85. } while (try-- && ibm4704_error);
  86. return data;
  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. uint8_t data = 0;
  105. bool parity = true; // odd parity
  106. ibm4704_error = IBM4704_ERR_NONE;
  107. idle();
  108. _delay_us(5); // wait for line settles
  109. /* start bit */
  110. WAIT(clock_lo, 100, 0x11); // wait for keyboard to send
  111. WAIT(data_hi, 100, 0x12); // can be delayed that long
  112. WAIT(clock_hi, 100, 0x13); // first rising edge which can take longer
  113. /* data */
  114. for (uint8_t i = 0; i < 8; i++) {
  115. WAIT(clock_hi, 100, 0x20+i);
  116. //_delay_us(5);
  117. if (data_in()) {
  118. parity = !parity;
  119. data |= (1<<i);
  120. }
  121. WAIT(clock_lo, 150, 0x28+i);
  122. }
  123. /* parity */
  124. WAIT(clock_hi, 100, 0x17);
  125. if (data_in() != parity) {
  126. ibm4704_error = IBM4704_ERR_PARITY;
  127. goto ERROR;
  128. }
  129. WAIT(clock_lo, 150, 0x18);
  130. /* stop bit */
  131. WAIT(clock_hi, 100, 0x19);
  132. WAIT(data_lo, 1, 0x19);
  133. inhibit();
  134. _delay_us(200); // wait to recover clock to hi
  135. return data;
  136. ERROR:
  137. if (ibm4704_error > 0x12) {
  138. xprintf("x%02X ", ibm4704_error);
  139. }
  140. inhibit();
  141. _delay_us(200); // wait to recover clock to hi
  142. return -1;
  143. }