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.

next_kbd.c 6.1KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204
  1. /*
  2. NeXT non-ADB Keyboard Protocol
  3. Copyright 2013, Benjamin Gould ([email protected])
  4. Based on:
  5. TMK firmware code Copyright 2011,2012 Jun WAKO <[email protected]>
  6. Arduino code by "Ladyada" Limor Fried (http://ladyada.net/, http://adafruit.com/), released under BSD license
  7. Timing reference thanks to http://m0115.web.fc2.com/ (dead link), http://cfile7.uf.tistory.com/image/14448E464F410BF22380BB
  8. Pinouts thanks to http://www.68k.org/~degs/nextkeyboard.html
  9. Keycodes from http://ftp.netbsd.org/pub/NetBSD/NetBSD-release-6/src/sys/arch/next68k/dev/
  10. This software is licensed with a Modified BSD License.
  11. All of this is supposed to be Free Software, Open Source, DFSG-free,
  12. GPL-compatible, and OK to use in both free and proprietary applications.
  13. Additions and corrections to this file are welcome.
  14. Redistribution and use in source and binary forms, with or without
  15. modification, are permitted provided that the following conditions are met:
  16. * Redistributions of source code must retain the above copyright
  17. notice, this list of conditions and the following disclaimer.
  18. * Redistributions in binary form must reproduce the above copyright
  19. notice, this list of conditions and the following disclaimer in
  20. the documentation and/or other materials provided with the
  21. distribution.
  22. * Neither the name of the copyright holders nor the names of
  23. contributors may be used to endorse or promote products derived
  24. from this software without specific prior written permission.
  25. THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
  26. AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
  27. IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
  28. ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
  29. LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
  30. CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
  31. SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
  32. INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
  33. CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
  34. ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
  35. POSSIBILITY OF SUCH DAMAGE.
  36. */
  37. #include <stdint.h>
  38. #include <stdbool.h>
  39. #include <util/atomic.h>
  40. #include <util/delay.h>
  41. #include "next_kbd.h"
  42. #include "debug.h"
  43. static inline void out_lo(void);
  44. static inline void out_hi(void);
  45. static inline void query(void);
  46. static inline void reset(void);
  47. static inline uint32_t response(void);
  48. #define out_hi_delay(intervals) do { out_hi(); _delay_us(NEXT_KBD_TIMING * intervals); } while (0);
  49. #define out_lo_delay(intervals) do { out_lo(); _delay_us(NEXT_KBD_TIMING * intervals); } while (0);
  50. #define query_delay(intervals) do { query(); _delay_us(NEXT_KBD_TIMING * intervals); } while (0);
  51. #define reset_delay(intervals) do { reset(); _delay_us(NEXT_KBD_TIMING * intervals); } while (0);
  52. void next_kbd_init(void)
  53. {
  54. out_hi();
  55. NEXT_KBD_IN_DDR &= ~(1<<NEXT_KBD_IN_BIT); // KBD_IN to input
  56. NEXT_KBD_IN_PORT |= (1<<NEXT_KBD_IN_BIT); // KBD_IN pull up
  57. query_delay(5);
  58. reset_delay(8);
  59. query_delay(5);
  60. reset_delay(8);
  61. }
  62. void next_kbd_set_leds(bool left, bool right)
  63. {
  64. out_lo_delay(9);
  65. out_hi_delay(3);
  66. out_lo_delay(1);
  67. if (left) {
  68. out_hi_delay(1);
  69. } else {
  70. out_lo_delay(1);
  71. }
  72. if (right) {
  73. out_hi_delay(1);
  74. } else {
  75. out_lo_delay(1);
  76. }
  77. out_lo_delay(7);
  78. out_hi();
  79. }
  80. #define NEXT_KBD_READ (NEXT_KBD_IN_PIN&(1<<NEXT_KBD_IN_BIT))
  81. uint32_t next_kbd_recv(void)
  82. {
  83. // First check to make sure that the keyboard is actually connected;
  84. // if not, just return
  85. // TODO: reflect the status of the keyboard in a return code
  86. if (!NEXT_KBD_READ) {
  87. sei();
  88. return 0;
  89. }
  90. query();
  91. uint32_t resp = response();
  92. return resp;
  93. }
  94. static inline uint32_t response(void)
  95. {
  96. cli();
  97. // try a 5ms read; this should be called after the query method has
  98. // been run so if a key is pressed we should get a response within
  99. // 5ms; if not then send a reset and exit
  100. uint8_t i = 0;
  101. uint32_t data = 0;
  102. uint16_t reset_timeout = 50000;
  103. while (NEXT_KBD_READ && reset_timeout) {
  104. asm(""); _delay_us(1); reset_timeout--;
  105. }
  106. if (!reset_timeout) {
  107. reset();
  108. sei();
  109. return 0;
  110. }
  111. _delay_us(NEXT_KBD_TIMING / 2);
  112. for (; i < 22; i++)
  113. {
  114. if (NEXT_KBD_READ)
  115. {
  116. data |= ((uint32_t) 1 << i);
  117. /* Note:
  118. * My testing with the ATmega32u4 showed that there might
  119. * something wrong with the timing here; by the end of the
  120. * second data byte some of the modifiers can get bumped out
  121. * to the next bit over if we just cycle through the data
  122. * based on the expected interval. There is a bit (i = 10)
  123. * in the middle of the data that is always on followed by
  124. * one that is always off - so we'll use that to reset our
  125. * timing in case we've gotten ahead of the keyboard;
  126. */
  127. if (i == 10)
  128. {
  129. i++;
  130. while (NEXT_KBD_READ) ;
  131. _delay_us(NEXT_KBD_TIMING / 2);
  132. }
  133. } else {
  134. /* redundant - but I don't want to remove if it might screw
  135. * up the timing
  136. */
  137. data |= ((uint32_t) 0 << i);
  138. }
  139. _delay_us(NEXT_KBD_TIMING);
  140. }
  141. sei();
  142. return data;
  143. }
  144. static inline void out_lo(void)
  145. {
  146. NEXT_KBD_OUT_PORT &= ~(1<<NEXT_KBD_OUT_BIT);
  147. NEXT_KBD_OUT_DDR |= (1<<NEXT_KBD_OUT_BIT);
  148. }
  149. static inline void out_hi(void)
  150. {
  151. /* input with pull up */
  152. NEXT_KBD_OUT_DDR &= ~(1<<NEXT_KBD_OUT_BIT);
  153. NEXT_KBD_OUT_PORT |= (1<<NEXT_KBD_OUT_BIT);
  154. }
  155. static inline void query(void)
  156. {
  157. out_lo_delay(5);
  158. out_hi_delay(1);
  159. out_lo_delay(3);
  160. out_hi();
  161. }
  162. static inline void reset(void)
  163. {
  164. out_lo_delay(1);
  165. out_hi_delay(4);
  166. out_lo_delay(1);
  167. out_hi_delay(6);
  168. out_lo_delay(10);
  169. out_hi();
  170. }