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 14KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494
  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. static void matrix_clear(void);
  27. #ifdef MATRIX_HAS_GHOST
  28. static bool matrix_has_ghost_in_row(uint8_t row);
  29. #endif
  30. /*
  31. * Matrix Array usage:
  32. * 'Scan Code Set 2' is assigned into 256(32x8)cell matrix.
  33. * Hmm, it is very sparse and not efficient :(
  34. *
  35. * Notes:
  36. * Both 'Hanguel/English'(F1) and 'Hanja'(F2) collide with 'Delete'(E0 71) and 'Down'(E0 72).
  37. * These two Korean keys need exceptional handling and are not supported for now. Sorry.
  38. *
  39. * 8bit wide
  40. * +---------+
  41. * 0| |
  42. * :| XX | 00-7F for normal codes(without E0-prefix)
  43. * f|_________|
  44. * 10| |
  45. * :| E0 YY | 80-FF for E0-prefixed codes
  46. * 1f| | (<YY>|0x80) is used as matrix position.
  47. * +---------+
  48. *
  49. * Exceptions:
  50. * 0x83: F7(0x83) This is a normal code but beyond 0x7F.
  51. * 0xFC: PrintScreen
  52. * 0xFE: Pause
  53. */
  54. static uint8_t matrix[MATRIX_ROWS];
  55. #define ROW(code) (code>>3)
  56. #define COL(code) (code&0x07)
  57. // matrix positions for exceptional keys
  58. #define F7 (0x83)
  59. #define PRINT_SCREEN (0xFC)
  60. #define PAUSE (0xFE)
  61. static bool is_modified = false;
  62. inline
  63. uint8_t matrix_rows(void)
  64. {
  65. return MATRIX_ROWS;
  66. }
  67. inline
  68. uint8_t matrix_cols(void)
  69. {
  70. return MATRIX_COLS;
  71. }
  72. void matrix_init(void)
  73. {
  74. debug_enable = true;
  75. ps2_host_init();
  76. // initialize matrix state: all keys off
  77. for (uint8_t i=0; i < MATRIX_ROWS; i++) matrix[i] = 0x00;
  78. return;
  79. }
  80. /*
  81. * PS/2 Scan Code Set 2: Exceptional Handling
  82. *
  83. * There are several keys to be handled exceptionally.
  84. * The scan code for these keys are varied or prefix/postfix'd
  85. * depending on modifier key state.
  86. *
  87. * Keyboard Scan Code Specification:
  88. * http://www.microsoft.com/whdc/archive/scancode.mspx
  89. * http://download.microsoft.com/download/1/6/1/161ba512-40e2-4cc9-843a-923143f3456c/scancode.doc
  90. *
  91. *
  92. * 1) Insert, Delete, Home, End, PageUp, PageDown, Up, Down, Right, Left
  93. * a) when Num Lock is off
  94. * modifiers | make | break
  95. * ----------+---------------------------+----------------------
  96. * Ohter | <make> | <break>
  97. * LShift | E0 F0 12 <make> | <break> E0 12
  98. * RShift | E0 F0 59 <make> | <break> E0 59
  99. * L+RShift | E0 F0 12 E0 F0 59 <make> | <break> E0 59 E0 12
  100. *
  101. * b) when Num Lock is on
  102. * modifiers | make | break
  103. * ----------+---------------------------+----------------------
  104. * Other | E0 12 <make> | <break> E0 F0 12
  105. * Shift'd | <make> | <break>
  106. *
  107. * Handling: These prefix/postfix codes are ignored.
  108. *
  109. *
  110. * 2) Keypad /
  111. * modifiers | make | break
  112. * ----------+---------------------------+----------------------
  113. * Ohter | <make> | <break>
  114. * LShift | E0 F0 12 <make> | <break> E0 12
  115. * RShift | E0 F0 59 <make> | <break> E0 59
  116. * L+RShift | E0 F0 12 E0 F0 59 <make> | <break> E0 59 E0 12
  117. *
  118. * Handling: These prefix/postfix codes are ignored.
  119. *
  120. *
  121. * 3) PrintScreen
  122. * modifiers | make | break
  123. * ----------+--------------+-----------------------------------
  124. * Other | E0 12 E0 7C | E0 F0 7C E0 F0 12
  125. * Shift'd | E0 7C | E0 F0 7C
  126. * Control'd | E0 7C | E0 F0 7C
  127. * Alt'd | 84 | F0 84
  128. *
  129. * Handling: These prefix/postfix codes are ignored, and both scan codes
  130. * 'E0 7C' and 84 are seen as PrintScreen.
  131. *
  132. * 4) Pause
  133. * modifiers | make(no break code)
  134. * ----------+--------------------------------------------------
  135. * Other | E1 14 77 E1 F0 14 F0 77
  136. * Control'd | E0 7E E0 F0 7E
  137. *
  138. * Handling: Both code sequences are treated as a whole.
  139. * And we need a ad hoc 'pseudo break code' hack to get the key off
  140. * because it has no break code.
  141. *
  142. */
  143. uint8_t matrix_scan(void)
  144. {
  145. // scan code reading states
  146. static enum {
  147. INIT,
  148. F0,
  149. E0,
  150. E0_F0,
  151. // Pause
  152. E1,
  153. E1_14,
  154. E1_14_77,
  155. E1_14_77_E1,
  156. E1_14_77_E1_F0,
  157. E1_14_77_E1_F0_14,
  158. E1_14_77_E1_F0_14_F0,
  159. // Control'd Pause
  160. E0_7E,
  161. E0_7E_E0,
  162. E0_7E_E0_F0,
  163. } state = INIT;
  164. is_modified = false;
  165. // 'pseudo break code' hack
  166. if (matrix_is_on(ROW(PAUSE), COL(PAUSE))) {
  167. matrix_break(PAUSE);
  168. }
  169. uint8_t code = ps2_host_recv();
  170. if (code) xprintf("%i\r\n", code);
  171. if (!ps2_error) {
  172. switch (state) {
  173. case INIT:
  174. switch (code) {
  175. case 0xE0:
  176. state = E0;
  177. break;
  178. case 0xF0:
  179. state = F0;
  180. break;
  181. case 0xE1:
  182. state = E1;
  183. break;
  184. case 0x83: // F7
  185. matrix_make(F7);
  186. state = INIT;
  187. break;
  188. case 0x84: // Alt'd PrintScreen
  189. matrix_make(PRINT_SCREEN);
  190. state = INIT;
  191. break;
  192. case 0x00: // Overrun [3]p.25
  193. matrix_clear();
  194. clear_keyboard();
  195. print("Overrun\n");
  196. state = INIT;
  197. break;
  198. case 0xAA: // Self-test passed
  199. case 0xFC: // Self-test failed
  200. printf("BAT %s\n", (code == 0xAA) ? "OK" : "NG");
  201. led_set(host_keyboard_leds());
  202. state = INIT;
  203. break;
  204. default: // normal key make
  205. if (code < 0x80) {
  206. matrix_make(code);
  207. } else {
  208. matrix_clear();
  209. clear_keyboard();
  210. xprintf("unexpected scan code at INIT: %02X\n", code);
  211. }
  212. state = INIT;
  213. }
  214. break;
  215. case E0: // E0-Prefixed
  216. switch (code) {
  217. case 0x12: // to be ignored
  218. case 0x59: // to be ignored
  219. state = INIT;
  220. break;
  221. case 0x7E: // Control'd Pause
  222. state = E0_7E;
  223. break;
  224. case 0xF0:
  225. state = E0_F0;
  226. break;
  227. default:
  228. if (code < 0x80) {
  229. matrix_make(code|0x80);
  230. } else {
  231. matrix_clear();
  232. clear_keyboard();
  233. xprintf("unexpected scan code at E0: %02X\n", code);
  234. }
  235. state = INIT;
  236. }
  237. break;
  238. case F0: // Break code
  239. switch (code) {
  240. case 0x83: // F7
  241. matrix_break(F7);
  242. state = INIT;
  243. break;
  244. case 0x84: // Alt'd PrintScreen
  245. matrix_break(PRINT_SCREEN);
  246. state = INIT;
  247. break;
  248. case 0xF0:
  249. matrix_clear();
  250. clear_keyboard();
  251. xprintf("unexpected scan code at F0: F0(clear and cont.)\n");
  252. break;
  253. default:
  254. if (code < 0x80) {
  255. matrix_break(code);
  256. } else {
  257. matrix_clear();
  258. clear_keyboard();
  259. xprintf("unexpected scan code at F0: %02X\n", code);
  260. }
  261. state = INIT;
  262. }
  263. break;
  264. case E0_F0: // Break code of E0-prefixed
  265. switch (code) {
  266. case 0x12: // to be ignored
  267. case 0x59: // to be ignored
  268. state = INIT;
  269. break;
  270. default:
  271. if (code < 0x80) {
  272. matrix_break(code|0x80);
  273. } else {
  274. matrix_clear();
  275. clear_keyboard();
  276. xprintf("unexpected scan code at E0_F0: %02X\n", code);
  277. }
  278. state = INIT;
  279. }
  280. break;
  281. // following are states of Pause
  282. case E1:
  283. switch (code) {
  284. case 0x14:
  285. state = E1_14;
  286. break;
  287. default:
  288. state = INIT;
  289. }
  290. break;
  291. case E1_14:
  292. switch (code) {
  293. case 0x77:
  294. state = E1_14_77;
  295. break;
  296. default:
  297. state = INIT;
  298. }
  299. break;
  300. case E1_14_77:
  301. switch (code) {
  302. case 0xE1:
  303. state = E1_14_77_E1;
  304. break;
  305. default:
  306. state = INIT;
  307. }
  308. break;
  309. case E1_14_77_E1:
  310. switch (code) {
  311. case 0xF0:
  312. state = E1_14_77_E1_F0;
  313. break;
  314. default:
  315. state = INIT;
  316. }
  317. break;
  318. case E1_14_77_E1_F0:
  319. switch (code) {
  320. case 0x14:
  321. state = E1_14_77_E1_F0_14;
  322. break;
  323. default:
  324. state = INIT;
  325. }
  326. break;
  327. case E1_14_77_E1_F0_14:
  328. switch (code) {
  329. case 0xF0:
  330. state = E1_14_77_E1_F0_14_F0;
  331. break;
  332. default:
  333. state = INIT;
  334. }
  335. break;
  336. case E1_14_77_E1_F0_14_F0:
  337. switch (code) {
  338. case 0x77:
  339. matrix_make(PAUSE);
  340. state = INIT;
  341. break;
  342. default:
  343. state = INIT;
  344. }
  345. break;
  346. // Following are states of Control'd Pause
  347. case E0_7E:
  348. if (code == 0xE0)
  349. state = E0_7E_E0;
  350. else
  351. state = INIT;
  352. break;
  353. case E0_7E_E0:
  354. if (code == 0xF0)
  355. state = E0_7E_E0_F0;
  356. else
  357. state = INIT;
  358. break;
  359. case E0_7E_E0_F0:
  360. if (code == 0x7E)
  361. matrix_make(PAUSE);
  362. state = INIT;
  363. break;
  364. default:
  365. state = INIT;
  366. }
  367. }
  368. // TODO: request RESEND when error occurs?
  369. /*
  370. if (PS2_IS_FAILED(ps2_error)) {
  371. uint8_t ret = ps2_host_send(PS2_RESEND);
  372. xprintf("Resend: %02X\n", ret);
  373. }
  374. */
  375. return 1;
  376. }
  377. bool matrix_is_modified(void)
  378. {
  379. return is_modified;
  380. }
  381. inline
  382. bool matrix_has_ghost(void)
  383. {
  384. #ifdef MATRIX_HAS_GHOST
  385. for (uint8_t i = 0; i < MATRIX_ROWS; i++) {
  386. if (matrix_has_ghost_in_row(i))
  387. return true;
  388. }
  389. #endif
  390. return false;
  391. }
  392. inline
  393. bool matrix_is_on(uint8_t row, uint8_t col)
  394. {
  395. return (matrix[row] & (1<<col));
  396. }
  397. inline
  398. uint8_t matrix_get_row(uint8_t row)
  399. {
  400. return matrix[row];
  401. }
  402. void matrix_print(void)
  403. {
  404. print("\nr/c 01234567\n");
  405. for (uint8_t row = 0; row < matrix_rows(); row++) {
  406. phex(row); print(": ");
  407. pbin_reverse(matrix_get_row(row));
  408. #ifdef MATRIX_HAS_GHOST
  409. if (matrix_has_ghost_in_row(row)) {
  410. print(" <ghost");
  411. }
  412. #endif
  413. print("\n");
  414. }
  415. }
  416. uint8_t matrix_key_count(void)
  417. {
  418. uint8_t count = 0;
  419. for (uint8_t i = 0; i < MATRIX_ROWS; i++) {
  420. count += bitpop(matrix[i]);
  421. }
  422. return count;
  423. }
  424. #ifdef MATRIX_HAS_GHOST
  425. inline
  426. static bool matrix_has_ghost_in_row(uint8_t row)
  427. {
  428. // no ghost exists in case less than 2 keys on
  429. if (((matrix[row] - 1) & matrix[row]) == 0)
  430. return false;
  431. // ghost exists in case same state as other row
  432. for (uint8_t i=0; i < MATRIX_ROWS; i++) {
  433. if (i != row && (matrix[i] & matrix[row]) == matrix[row])
  434. return true;
  435. }
  436. return false;
  437. }
  438. #endif
  439. inline
  440. static void matrix_make(uint8_t code)
  441. {
  442. if (!matrix_is_on(ROW(code), COL(code))) {
  443. matrix[ROW(code)] |= 1<<COL(code);
  444. is_modified = true;
  445. }
  446. }
  447. inline
  448. static void matrix_break(uint8_t code)
  449. {
  450. if (matrix_is_on(ROW(code), COL(code))) {
  451. matrix[ROW(code)] &= ~(1<<COL(code));
  452. is_modified = true;
  453. }
  454. }
  455. inline
  456. static void matrix_clear(void)
  457. {
  458. for (uint8_t i=0; i < MATRIX_ROWS; i++) matrix[i] = 0x00;
  459. }