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.

matrix.c 13KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428
  1. /*
  2. Copyright 2011 Jun Wako <[email protected]>
  3. This program is free software: you can redistribute it and/or modify
  4. it under the terms of the GNU General Public License as published by
  5. the Free Software Foundation, either version 2 of the License, or
  6. (at your option) any later version.
  7. This program is distributed in the hope that it will be useful,
  8. but WITHOUT ANY WARRANTY; without even the implied warranty of
  9. MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  10. GNU General Public License for more details.
  11. You should have received a copy of the GNU General Public License
  12. along with this program. If not, see <http://www.gnu.org/licenses/>.
  13. */
  14. #include <stdint.h>
  15. #include <stdbool.h>
  16. #include "action.h"
  17. #include "print.h"
  18. #include "util.h"
  19. #include "debug.h"
  20. #include "ps2.h"
  21. #include "host.h"
  22. #include "led.h"
  23. #include "matrix.h"
  24. static void matrix_make(uint8_t code);
  25. static void matrix_break(uint8_t code);
  26. /*
  27. * Matrix Array usage:
  28. * 'Scan Code Set 2' is assigned into 256(32x8)cell matrix.
  29. * Hmm, it is very sparse and not efficient :(
  30. *
  31. * Notes:
  32. * Both 'Hanguel/English'(F1) and 'Hanja'(F2) collide with 'Delete'(E0 71) and 'Down'(E0 72).
  33. * These two Korean keys need exceptional handling and are not supported for now. Sorry.
  34. *
  35. * 8bit wide
  36. * +---------+
  37. * 0| |
  38. * :| XX | 00-7F for normal codes(without E0-prefix)
  39. * f|_________|
  40. * 10| |
  41. * :| E0 YY | 80-FF for E0-prefixed codes
  42. * 1f| | (<YY>|0x80) is used as matrix position.
  43. * +---------+
  44. *
  45. * Exceptions:
  46. * 0x83: F7(0x83) This is a normal code but beyond 0x7F.
  47. * 0xFC: PrintScreen
  48. * 0xFE: Pause
  49. */
  50. static uint8_t matrix[MATRIX_ROWS];
  51. #define ROW(code) (code>>3)
  52. #define COL(code) (code&0x07)
  53. // matrix positions for exceptional keys
  54. #define F7 (0x83)
  55. #define PRINT_SCREEN (0xFC)
  56. #define PAUSE (0xFE)
  57. static bool is_modified = false;
  58. void matrix_init(void)
  59. {
  60. debug_enable = true;
  61. ps2_host_init();
  62. // initialize matrix state: all keys off
  63. for (uint8_t i=0; i < MATRIX_ROWS; i++) matrix[i] = 0x00;
  64. return;
  65. }
  66. /*
  67. * PS/2 Scan Code Set 2: Exceptional Handling
  68. *
  69. * There are several keys to be handled exceptionally.
  70. * The scan code for these keys are varied or prefix/postfix'd
  71. * depending on modifier key state.
  72. *
  73. * Keyboard Scan Code Specification:
  74. * http://www.microsoft.com/whdc/archive/scancode.mspx
  75. * http://download.microsoft.com/download/1/6/1/161ba512-40e2-4cc9-843a-923143f3456c/scancode.doc
  76. *
  77. *
  78. * 1) Insert, Delete, Home, End, PageUp, PageDown, Up, Down, Right, Left
  79. * a) when Num Lock is off
  80. * modifiers | make | break
  81. * ----------+---------------------------+----------------------
  82. * Ohter | <make> | <break>
  83. * LShift | E0 F0 12 <make> | <break> E0 12
  84. * RShift | E0 F0 59 <make> | <break> E0 59
  85. * L+RShift | E0 F0 12 E0 F0 59 <make> | <break> E0 59 E0 12
  86. *
  87. * b) when Num Lock is on
  88. * modifiers | make | break
  89. * ----------+---------------------------+----------------------
  90. * Other | E0 12 <make> | <break> E0 F0 12
  91. * Shift'd | <make> | <break>
  92. *
  93. * Handling: These prefix/postfix codes are ignored.
  94. *
  95. *
  96. * 2) Keypad /
  97. * modifiers | make | break
  98. * ----------+---------------------------+----------------------
  99. * Ohter | <make> | <break>
  100. * LShift | E0 F0 12 <make> | <break> E0 12
  101. * RShift | E0 F0 59 <make> | <break> E0 59
  102. * L+RShift | E0 F0 12 E0 F0 59 <make> | <break> E0 59 E0 12
  103. *
  104. * Handling: These prefix/postfix codes are ignored.
  105. *
  106. *
  107. * 3) PrintScreen
  108. * modifiers | make | break
  109. * ----------+--------------+-----------------------------------
  110. * Other | E0 12 E0 7C | E0 F0 7C E0 F0 12
  111. * Shift'd | E0 7C | E0 F0 7C
  112. * Control'd | E0 7C | E0 F0 7C
  113. * Alt'd | 84 | F0 84
  114. *
  115. * Handling: These prefix/postfix codes are ignored, and both scan codes
  116. * 'E0 7C' and 84 are seen as PrintScreen.
  117. *
  118. * 4) Pause
  119. * modifiers | make(no break code)
  120. * ----------+--------------------------------------------------
  121. * Other | E1 14 77 E1 F0 14 F0 77
  122. * Control'd | E0 7E E0 F0 7E
  123. *
  124. * Handling: Both code sequences are treated as a whole.
  125. * And we need a ad hoc 'pseudo break code' hack to get the key off
  126. * because it has no break code.
  127. *
  128. */
  129. uint8_t matrix_scan(void)
  130. {
  131. // scan code reading states
  132. static enum {
  133. INIT,
  134. F0,
  135. E0,
  136. E0_F0,
  137. // Pause
  138. E1,
  139. E1_14,
  140. E1_14_77,
  141. E1_14_77_E1,
  142. E1_14_77_E1_F0,
  143. E1_14_77_E1_F0_14,
  144. E1_14_77_E1_F0_14_F0,
  145. // Control'd Pause
  146. E0_7E,
  147. E0_7E_E0,
  148. E0_7E_E0_F0,
  149. } state = INIT;
  150. is_modified = false;
  151. // 'pseudo break code' hack
  152. if (matrix_is_on(ROW(PAUSE), COL(PAUSE))) {
  153. matrix_break(PAUSE);
  154. }
  155. uint8_t code = ps2_host_recv();
  156. if (code) xprintf("%i\r\n", code);
  157. if (!ps2_error) {
  158. switch (state) {
  159. case INIT:
  160. switch (code) {
  161. case 0xE0:
  162. state = E0;
  163. break;
  164. case 0xF0:
  165. state = F0;
  166. break;
  167. case 0xE1:
  168. state = E1;
  169. break;
  170. case 0x83: // F7
  171. matrix_make(F7);
  172. state = INIT;
  173. break;
  174. case 0x84: // Alt'd PrintScreen
  175. matrix_make(PRINT_SCREEN);
  176. state = INIT;
  177. break;
  178. case 0x00: // Overrun [3]p.25
  179. matrix_clear();
  180. clear_keyboard();
  181. print("Overrun\n");
  182. state = INIT;
  183. break;
  184. case 0xAA: // Self-test passed
  185. case 0xFC: // Self-test failed
  186. printf("BAT %s\n", (code == 0xAA) ? "OK" : "NG");
  187. led_set(host_keyboard_leds());
  188. state = INIT;
  189. break;
  190. default: // normal key make
  191. if (code < 0x80) {
  192. matrix_make(code);
  193. } else {
  194. matrix_clear();
  195. clear_keyboard();
  196. xprintf("unexpected scan code at INIT: %02X\n", code);
  197. }
  198. state = INIT;
  199. }
  200. break;
  201. case E0: // E0-Prefixed
  202. switch (code) {
  203. case 0x12: // to be ignored
  204. case 0x59: // to be ignored
  205. state = INIT;
  206. break;
  207. case 0x7E: // Control'd Pause
  208. state = E0_7E;
  209. break;
  210. case 0xF0:
  211. state = E0_F0;
  212. break;
  213. default:
  214. if (code < 0x80) {
  215. matrix_make(code|0x80);
  216. } else {
  217. matrix_clear();
  218. clear_keyboard();
  219. xprintf("unexpected scan code at E0: %02X\n", code);
  220. }
  221. state = INIT;
  222. }
  223. break;
  224. case F0: // Break code
  225. switch (code) {
  226. case 0x83: // F7
  227. matrix_break(F7);
  228. state = INIT;
  229. break;
  230. case 0x84: // Alt'd PrintScreen
  231. matrix_break(PRINT_SCREEN);
  232. state = INIT;
  233. break;
  234. case 0xF0:
  235. matrix_clear();
  236. clear_keyboard();
  237. xprintf("unexpected scan code at F0: F0(clear and cont.)\n");
  238. break;
  239. default:
  240. if (code < 0x80) {
  241. matrix_break(code);
  242. } else {
  243. matrix_clear();
  244. clear_keyboard();
  245. xprintf("unexpected scan code at F0: %02X\n", code);
  246. }
  247. state = INIT;
  248. }
  249. break;
  250. case E0_F0: // Break code of E0-prefixed
  251. switch (code) {
  252. case 0x12: // to be ignored
  253. case 0x59: // to be ignored
  254. state = INIT;
  255. break;
  256. default:
  257. if (code < 0x80) {
  258. matrix_break(code|0x80);
  259. } else {
  260. matrix_clear();
  261. clear_keyboard();
  262. xprintf("unexpected scan code at E0_F0: %02X\n", code);
  263. }
  264. state = INIT;
  265. }
  266. break;
  267. // following are states of Pause
  268. case E1:
  269. switch (code) {
  270. case 0x14:
  271. state = E1_14;
  272. break;
  273. default:
  274. state = INIT;
  275. }
  276. break;
  277. case E1_14:
  278. switch (code) {
  279. case 0x77:
  280. state = E1_14_77;
  281. break;
  282. default:
  283. state = INIT;
  284. }
  285. break;
  286. case E1_14_77:
  287. switch (code) {
  288. case 0xE1:
  289. state = E1_14_77_E1;
  290. break;
  291. default:
  292. state = INIT;
  293. }
  294. break;
  295. case E1_14_77_E1:
  296. switch (code) {
  297. case 0xF0:
  298. state = E1_14_77_E1_F0;
  299. break;
  300. default:
  301. state = INIT;
  302. }
  303. break;
  304. case E1_14_77_E1_F0:
  305. switch (code) {
  306. case 0x14:
  307. state = E1_14_77_E1_F0_14;
  308. break;
  309. default:
  310. state = INIT;
  311. }
  312. break;
  313. case E1_14_77_E1_F0_14:
  314. switch (code) {
  315. case 0xF0:
  316. state = E1_14_77_E1_F0_14_F0;
  317. break;
  318. default:
  319. state = INIT;
  320. }
  321. break;
  322. case E1_14_77_E1_F0_14_F0:
  323. switch (code) {
  324. case 0x77:
  325. matrix_make(PAUSE);
  326. state = INIT;
  327. break;
  328. default:
  329. state = INIT;
  330. }
  331. break;
  332. // Following are states of Control'd Pause
  333. case E0_7E:
  334. if (code == 0xE0)
  335. state = E0_7E_E0;
  336. else
  337. state = INIT;
  338. break;
  339. case E0_7E_E0:
  340. if (code == 0xF0)
  341. state = E0_7E_E0_F0;
  342. else
  343. state = INIT;
  344. break;
  345. case E0_7E_E0_F0:
  346. if (code == 0x7E)
  347. matrix_make(PAUSE);
  348. state = INIT;
  349. break;
  350. default:
  351. state = INIT;
  352. }
  353. }
  354. // TODO: request RESEND when error occurs?
  355. /*
  356. if (PS2_IS_FAILED(ps2_error)) {
  357. uint8_t ret = ps2_host_send(PS2_RESEND);
  358. xprintf("Resend: %02X\n", ret);
  359. }
  360. */
  361. return 1;
  362. }
  363. inline
  364. bool matrix_is_on(uint8_t row, uint8_t col)
  365. {
  366. return (matrix[row] & (1<<col));
  367. }
  368. inline
  369. uint8_t matrix_get_row(uint8_t row)
  370. {
  371. return matrix[row];
  372. }
  373. uint8_t matrix_key_count(void)
  374. {
  375. uint8_t count = 0;
  376. for (uint8_t i = 0; i < MATRIX_ROWS; i++) {
  377. count += bitpop(matrix[i]);
  378. }
  379. return count;
  380. }
  381. inline
  382. static void matrix_make(uint8_t code)
  383. {
  384. if (!matrix_is_on(ROW(code), COL(code))) {
  385. matrix[ROW(code)] |= 1<<COL(code);
  386. is_modified = true;
  387. }
  388. }
  389. inline
  390. static void matrix_break(uint8_t code)
  391. {
  392. if (matrix_is_on(ROW(code), COL(code))) {
  393. matrix[ROW(code)] &= ~(1<<COL(code));
  394. is_modified = true;
  395. }
  396. }
  397. void matrix_clear(void)
  398. {
  399. for (uint8_t i=0; i < MATRIX_ROWS; i++) matrix[i] = 0x00;
  400. }